征程6E/M快速上手實(shí)戰(zhàn)Sample-Codec
01 Codec 模塊簡述
Codec(Coder-Decoder)是指編****,用于壓縮或解壓縮視頻、圖像、音頻等媒體數(shù)據(jù);J6 Soc 中存在兩種硬件編解碼單元,分別是 VPU(Video process unit)和 JPU(Jpeg process unit),可提供 4K@90fps 的視頻編解碼能力和 4K@90fps 的圖像編解碼能力。
1.1 硬件特性1.1.1 JPU 硬件特性:
1.1.2 VPU 硬件特性:
1.2 軟件功能
MediaCodec 子系統(tǒng)會(huì)提供音視頻和圖像的編解碼組件,原始流封裝和視頻錄像等功能。該系統(tǒng)主要會(huì)封裝底層 codec 硬件資源和軟件編解碼庫,為上層提供編解碼能力。開發(fā)者可以基于提供的編解碼接口實(shí)現(xiàn) H265 和 H264 視頻的編解碼功能,也可以使用 JPEG 編碼功能將攝像頭數(shù)據(jù)存成 JPEG 圖片,還可以使用視頻錄像功能實(shí)現(xiàn)攝像頭數(shù)據(jù)的錄制。
1.2.1 整體框架:
1.2.2 控制接口:
hb_s32 hb_mm_mc_initialize(media_codec_context_t *context):初始化編碼或****,調(diào)用成功后 MediaCodec 進(jìn)入 MEDIA_CODEC_STATE_INITIALIZED 狀態(tài)。
hb_s32 hb_mm_mc_configure(media_codec_context_t *context):配置編碼或****,調(diào)用成功后 MediaCodec 進(jìn)入 MEDIA_CODEC_STATE_CONFIGURED 狀態(tài)。
hb_s32 hb_mm_mc_start(media_codec_context_t *context, const mc_av_codec_startup_params_t *info):啟動(dòng)編碼/解碼流程,MediaCodec 將創(chuàng)建編解碼實(shí)例、設(shè)置序列或解析數(shù)據(jù)流、注冊(cè) Framebuffer、編碼頭信息等,調(diào)用成功后 MediaCodec 進(jìn)入 MEDIA_CODEC_STATE_STARTED 狀態(tài)。
hb_s32 hb_mm_mc_stop(media_codec_context_t *context):停止編碼/解碼流程,退出所有子線程并釋放相關(guān)資源,調(diào)用成功后 MediaCodec 回到 MEDIA_CODEC_STATE_INITIALIZED 狀態(tài)。
hb_s32 hb_mm_mc_release(media_codec_context_t *context):釋放 MediaCodec 內(nèi)部所有資源,用戶需要在調(diào)用該函數(shù)前調(diào)用 hb_mm_mc_stop 來停止編解碼,操作成功后 MediaCodec 進(jìn)入 MEDIA_CODEC_STATE_UNINITIALIZED 狀態(tài)。
hb_s32 hb_mm_mc_queue_input_buffer(media_codec_context_t *context, media_codec_buffer_t *buffer, hb_s32 timeout):填充需要處理的 buffer 到 MediaCodec 中。
hb_s32 hb_mm_mc_dequeue_input_buffer(media_codec_context_t *context, media_codec_buffer_t *buffer, hb_s32 timeout):獲取輸入的 buffer。
hb_s32 hb_mm_mc_queue_output_buffer(media_codec_context_t *context, media_codec_buffer_t *buffer, hb_s32 timeout):返還處理完的 output buffer 到 MediaCodec 中。
hb_s32 hb_mm_mc_dequeue_output_buffer(media_codec_context_t *context, media_codec_buffer_t *buffer, media_codec_output_buffer_info_t *info, hb_s32 timeout):獲取輸出的 buffer。
1.2.3 碼率控制模式:
MediaCodec 支持對(duì) H264/H265 和 MJPEG 協(xié)議的碼率控制,分別支持 H264/H265 編碼通道的 CBR、VBR、AVBR、FixQp 和 QpMap 五種碼率控制方式,以及支持 MJPGE 編碼通道的 FixQp 碼率控制方式。
*1.2.3.1 CBR 說明:*
CBR 表示恒定碼率,能夠保證整體的編碼碼率穩(wěn)定。下面是 CBR 模式下各個(gè)參數(shù)含義:
*1.2.3.2 VBR 說明:*
VBR 表示可變碼率,簡單場景分配比較大的 qp,壓縮率小,質(zhì)量高。復(fù)雜場景分配較小 qp,可以保證編碼圖像的質(zhì)量穩(wěn)定。下面是 VBR 模式下各個(gè)參數(shù)含義:
1.2.3.3 AVBR 說明:
ABR 表示恒定平均目標(biāo)碼率,簡單場景分配較低碼率,復(fù)雜場景分配足夠碼率,使得有限的碼率能夠在不同場景下合理分配,這類似 VBR。同時(shí)一定時(shí)間內(nèi),平均碼率又接近設(shè)置的目標(biāo)碼率,這樣可以控制輸出文件的大小,這又類似 CBR??梢哉J(rèn)為是 CBR 和 VBR 的折中方案,產(chǎn)生碼率和圖像質(zhì)量相對(duì)穩(wěn)定的碼流。下面是 AVBR 模式下各個(gè)參數(shù)含義:
1.2.3.4 FixQp 說明:
FixQp 表示固定每一個(gè) I 幀、P 幀的 QP 值,對(duì)于 I/P 幀可以分別設(shè)值。下面是 FixQp 模式下各個(gè)參數(shù)含義:
1.2.3.5 QPMAP 說明:
1.2.4 編碼效果:
根據(jù)當(dāng)前客戶使用 codec 進(jìn)行視頻編碼的場景,多將碼率模式設(shè)置為 CBR,當(dāng)編碼的場景較為復(fù)雜時(shí),為了保證視頻質(zhì)量,硬件會(huì)自動(dòng)提高碼率值,導(dǎo)致輸出的視頻較預(yù)期更大。因此為了兼顧視頻質(zhì)量和實(shí)際碼率,需要統(tǒng)籌 bit_rate 和 max_qp_I/P 值的設(shè)置。下面給出了全 I 幀模式下,不同復(fù)雜場景下,碼率設(shè)置為 15000kbps 時(shí),不同 max_qp_I 下實(shí)際碼率和 qp 的情況(不同場景復(fù)雜程度不同,下列數(shù)據(jù)僅供參考):
H264/H265 編碼支持 GOP 結(jié)構(gòu)的設(shè)置,用戶可從預(yù)置的 3 種 GOP 結(jié)構(gòu)種選擇,也可自定義 GOP 結(jié)構(gòu)。
GOP 結(jié)構(gòu)表可定義一組周期性的 GOP 結(jié)構(gòu),該 GOP 結(jié)構(gòu)將用于整個(gè)編碼過程。單個(gè)結(jié)構(gòu)表中的元素如下表所示,其中可以指定該圖像的參考幀,如果 IDR 幀后的其他幀指定的參考幀為 IDR 幀前的數(shù)據(jù)幀,編碼器內(nèi)部會(huì)自動(dòng)處理這種情況使其不參考其他幀,用戶無需關(guān)心這種情況。用戶在自定義 GOP 結(jié)構(gòu)時(shí)需要指明結(jié)構(gòu)表的數(shù)量,最多可定義 3 個(gè)結(jié)構(gòu)表,結(jié)構(gòu)表的順序需要按照解碼順序排列。下面表示了結(jié)構(gòu)表中各個(gè)元素的含義:
征程6 中一共支持設(shè)置九種 GOP 預(yù)置結(jié)構(gòu):
02 Codec-Sample 使用
編碼 yuv 圖像, 生成 h264/h265 視頻或 jpg 圖片。
2.1 encoder** **2.1.1 調(diào)用流程
采用 MediaCodec 的 poll 模式來解耦輸入和輸出,可使編碼幀率性能達(dá)到最優(yōu)。在主線程中灌 YUV 數(shù)據(jù):取出一個(gè)空的 input buffer,配置 YUV 數(shù)據(jù)的地址信息(如 phys addr),再 queue input buffer 并通知編碼器處理該幀數(shù)據(jù);另一個(gè)線程取輸出碼流:通過 select 接收硬件編碼完成通知,取出一個(gè)硬件填滿輸出碼流的 output buffer,將編碼結(jié)果寫到文件中后歸還 output buffer。
check_and_init_test:打開輸入文件(yuv),并打開內(nèi)存管理模塊申請(qǐng)內(nèi)存緩沖;
hb_mm_mc_initialize:初始化編碼或****,調(diào)用成功后 MediaCodec 進(jìn)入 MEDIA_CODEC_STATE_INITIALIZED 狀態(tài);
hb_mm_mc_configure:配置編碼或****,調(diào)用成功后 MediaCodec 進(jìn)入 MEDIA_CODEC_STATE_CONFIGURED 狀態(tài);
hb_mm_mc_start:啟動(dòng)編碼/解碼流程,MediaCodec 將創(chuàng)建編解碼實(shí)例、設(shè)置序列或解析數(shù)據(jù)流、注冊(cè) Framebuffer、編碼頭信息等,調(diào)用成功后 MediaCodec 進(jìn)入 MEDIA_CODEC_STATE_STARTED 狀態(tài);
hb_mm_mc_dequeue_input_buffer:獲取輸入的 buffer;
read_input_frames:從輸入文件(yuv)中讀取視頻幀數(shù)據(jù),并將其刷新到 buffer 中;
hb_mm_mc_queue_input_buffer:填充需要處理的 buffer 到 MediaCodec 中;
hb_mm_mc_dequeue_output_buffer:獲取輸出的 buffer;
write_output_streams:outputbuffer 寫入 outFile 中;
hb_mm_mc_queue_output_buffer:返還處理完的 output buffer 到 MediaCodec 中;
hb_mm_mc_stop:停止編碼/解碼流程,退出所有子線程并釋放相關(guān)資源,調(diào)用成功后 MediaCodec 回到 MEDIA_CODEC_STATE_INITIALIZED 狀態(tài);
hb_mm_mc_release:釋放 MediaCodec 內(nèi)部所有資源,操作成功后 MediaCodec 進(jìn)入 MEDIA_CODEC_STATE_UNINITIALIZED 狀態(tài)。
2.1.2 源碼主干:
#Sample源碼路徑
/test/samples/platform_samples/source/S83_Sample/S83E04_Module/codec_sample
Encoder:
void do_sync_encoding(void *arg)
{
hb_s32 ret = 0;
MediaCodecTestContext *ctx = (MediaCodecTestContext *)arg;
media_codec_context_t *context = NULL;
media_codec_buffer_t inputBuffer;
media_codec_buffer_t outputBuffer;
media_codec_output_buffer_info_t info;
ret = check_and_init_test(ctx);
if (ret != 0) {
printf("check_and_init_test failed(%d).\n", ret);
return;
}
context = ctx->context;
ret = hb_mm_mc_initialize(context);
if (ret != 0) {
printf("hb_mm_mc_initialize failed(%d).\n", ret);
return;
}
// set_message(ctx);
ret = hb_mm_mc_configure(context);
if (ret != 0) {
printf("hb_mm_mc_configure failed(%d).\n", ret);
hb_mm_mc_release(context);
return;
}
mc_av_codec_startup_params_t startup_params;
startup_params.video_enc_startup_params.receive_frame_number = 0;
ret = hb_mm_mc_start(context, &startup_params);
if (ret != 0) {
printf("hb_mm_mc_start failed(%d).\n", ret);
hb_mm_mc_release(context);
return;
}
do {
// process input buffers
memset(&inputBuffer, 0x00, sizeof(media_codec_buffer_t));
ret = hb_mm_mc_dequeue_input_buffer(context, &inputBuffer, 3000);
if (ret == 0) {
ret = read_input_frames(ctx, &inputBuffer);
if (ret <= 0) {
printf("There is no more input data(ret=%d)!\n", ret);
inputBuffer.vframe_buf.size = 0;
inputBuffer.vframe_buf.frame_end = TRUE;
}
ctx->input_num++;
// ASSERT_EQ(do_encode_params_setting(ctx, &inputBuffer), 0);
ret = hb_mm_mc_queue_input_buffer(context, &inputBuffer, 100);
if (ret != 0) {
break;
}
} else {
printf("dequeue input buffer fail(%d).\n", ret);
if (ret != (int32_t)HB_MEDIA_ERR_WAIT_TIMEOUT) {
break;
}
}
// process output buffers
memset(&outputBuffer, 0x00, sizeof(media_codec_buffer_t));
memset(&info, 0x00, sizeof(media_codec_output_buffer_info_t));
ret = hb_mm_mc_dequeue_output_buffer(context, &outputBuffer, &info, 3000);
if (ret == 0) {
write_output_streams(ctx, &outputBuffer);
ret = hb_mm_mc_queue_output_buffer(context, &outputBuffer, 100);
if (outputBuffer.vstream_buf.stream_end) {
printf("There is no more output data!\n");
break;
}
if (ret) {
break;
}
} else {
printf("dequeue output buffer fail(ret=0x%x).\n", ret);
if (ret != (int32_t)HB_MEDIA_ERR_WAIT_TIMEOUT) {
break;
}
}
} while(TRUE);
ret = hb_mm_mc_stop(context);
if (ret != 0) {
printf("hb_mm_mc_stop failed(%d).\n", ret);
}
ret = hb_mm_mc_release(context);
if (ret != 0) {
printf("hb_mm_mc_release failed(%d).\n", ret);
}
check_and_release_test(ctx);
}
2.2 decoder
VPU/JPU 從 DDR 中獲得 H265/H264/JPG 輸入源,經(jīng)過硬件解碼后生成 yuv 圖像
2.2.1 調(diào)用流程
check_and_init_test:打開輸入文件(h265),并打開內(nèi)存管理模塊申請(qǐng)內(nèi)存緩沖;
hb_mm_mc_initialize:初始化編碼或****,調(diào)用成功后 MediaCodec 進(jìn)入 MEDIA_CODEC_STATE_INITIALIZED 狀態(tài);
hb_mm_mc_configure:配置編碼或****,調(diào)用成功后 MediaCodec 進(jìn)入 MEDIA_CODEC_STATE_CONFIGURED 狀態(tài);
hb_mm_mc_start:啟動(dòng)編碼/解碼流程,MediaCodec 將創(chuàng)建編解碼實(shí)例、設(shè)置序列或解析數(shù)據(jù)流、注冊(cè) Framebuffer、編碼頭信息等,調(diào)用成功后 MediaCodec 進(jìn)入 MEDIA_CODEC_STATE_STARTED 狀態(tài);
hb_mm_mc_dequeue_input_buffer:獲取輸入的 buffer;
hb_mm_mc_dequeue_output_buffer:獲取輸出的 buffer;
write_output_streams:outputbuffer 寫入 outFile 中;
hb_mm_mc_queue_output_buffer:返還處理完的 output buffer 到 MediaCodec 中;
hb_mm_mc_stop:停止編碼/解碼流程,退出所有子線程并釋放相關(guān)資源,調(diào)用成功后 MediaCodec 回到 MEDIA_CODEC_STATE_INITIALIZED 狀態(tài);
hb_mm_mc_release:釋放 MediaCodec 內(nèi)部所有資源,操作成功后 MediaCodec 進(jìn)入 MEDIA_CODEC_STATE_UNINITIALIZED 狀態(tài)。
** **2.2.2 源碼主干:
void do_sync_decoding(void *arg)
{
int ret = 0;
MediaCodecTestContext *ctx = (MediaCodecTestContext *)arg;
media_codec_context_t *context = NULL;
media_codec_buffer_t inputBuffer;
media_codec_buffer_t outputBuffer;
media_codec_output_buffer_info_t info;
ret = check_and_init_test(ctx);
if (ret != 0) {
printf("check_and_init_test failed(%d).\n", ret);
return;
} context = ctx->context;
context = ctx->context;
ret = hb_mm_mc_initialize(context);
if (ret != 0) {
printf("hb_mm_mc_initialize failed(%d).\n", ret);
return;
}
ret = hb_mm_mc_configure(context);
if (ret != 0) {
printf("hb_mm_mc_configure failed(%d).\n", ret);
hb_mm_mc_release(context);
return;
}
mc_av_codec_startup_params_t startup_params;
startup_params.video_enc_startup_params.receive_frame_number = 0;
ret = hb_mm_mc_start(context, &startup_params);
if (ret != 0) {
printf("hb_mm_mc_start failed(%d).\n", ret);
hb_mm_mc_release(context);
return;
}
do {
// process input buffers
ret = hb_mm_mc_dequeue_input_buffer(context, &inputBuffer, 3000);
if (ret == 0) {
ret = read_input_streams(ctx, &inputBuffer);
if (ret <= 0) {
printf("There is no more input data(ret=%d)!\n", ret);
inputBuffer.vstream_buf.stream_end = TRUE;
inputBuffer.vstream_buf.size = 0;
ctx->lastStream = 1;
}
ret = hb_mm_mc_queue_input_buffer(context, &inputBuffer, 100);
if (ret != 0) {
break;
}
} else {
if (ret != (int32_t)HB_MEDIA_ERR_WAIT_TIMEOUT) {
char info[256];
hb_mm_strerror(ret, info, 256);
printf("dequeue input buffer fail.(%s)\n", info);
break;
}
}
// process output buffers
memset(&outputBuffer, 0x00, sizeof(media_codec_buffer_t));
memset(&info, 0x00, sizeof(media_codec_output_buffer_info_t));
ret = hb_mm_mc_dequeue_output_buffer(context, &outputBuffer, &info, 100);
if (ret == 0) {
printf("info.video_frame_info.nalu_type %d\n", info.video_frame_info.nalu_type);
write_output_frames(ctx, &outputBuffer);
if (ctx->enable_get_userdata) {
mc_user_data_buffer_t userdata = {0};
ret = hb_mm_mc_get_user_data(context, &userdata, 0);
if (!ret) {
printf("Get userdata %d:\n", userdata.size);
for (uint32_t i = 0; i < userdata.size; i++) {
if (i < 16) {
printf("userdata[i]:%x\n", userdata.virt_addr[i]);
} else {
printf("userdata[i]:%c\n", userdata.virt_addr[i]);
}
}
ret = hb_mm_mc_release_user_data(context, &userdata);
} else {
ret = 0;
}
}
ret = hb_mm_mc_queue_output_buffer(context, &outputBuffer, 100);
if (outputBuffer.vframe_buf.frame_end) {
printf("There is no more output data!\n");
break;
}
if (ret) {
break;
}
} else {
char info[256];
hb_mm_strerror(ret, info, 256);
printf("dequeue output buffer fail.(%s)\n", info);
if (ret != (int32_t)HB_MEDIA_ERR_WAIT_TIMEOUT) {
break;
}
}
} while (TRUE);
ret = hb_mm_mc_stop(context);
if (ret != 0) {
printf("hb_mm_mc_stop failed(%d).\n", ret);
}
ret = hb_mm_mc_release(context);
if (ret != 0) {
printf("hb_mm_mc_release failed(%d).\n", ret);
}
check_and_release_test(ctx);
}
2.3 編譯&運(yùn)行
獲取 AppSDK 包后,進(jìn)入 appuser 執(zhí)行:
*其中 hbrootfs-sdk_0.0.1.XXX_all.deb 是地平線自己的庫和頭文件,rootfs-sdk-focal_0.0.1.XXX_all.deb 是系統(tǒng)庫,aarch64-linux-hb-gcc_12.2.0_amd64.deb 是 gcc 12.2.0 工具鏈,目前在 ubuntu22.04 非 docker 環(huán)境下運(yùn)行正常。其它環(huán)境不能保證。
dpkg-deb -x rootfs-sdk*.deb ./sdk
dpkg-deb -x hbrootfs-sdk*.deb ./sdk
##移動(dòng)sdk庫路徑,本文檔放入/usr/lib中
sudo mv sdk/ /usr/lib
進(jìn)入 toolchain 執(zhí)行:
dpkg -x aarch64-linux-hb-gcc_12.2.0_amd64.deb ./arm-gnu-toolchain
##移動(dòng)toolchain庫路徑,本文檔放入/usr/lib中
sudo mv arm-gnu-toolchain/ /usr/lib
nano ~/.bashrc
##添加系統(tǒng)路徑
export PATH="/usr/lib/arm-gnu-toolchain/bin:$PATH"
export LD_LIBRARY_PATH="/usr/lib/arm-gnu-toolchain/lib:$LD_LIBRARY_PATH"
##
source ~/.bashrc
Sample 代碼路徑:
#Sample源碼路徑
/test/samples/platform_samples/source/S83_Sample/S83E04_Module/codec_sample
運(yùn)行參數(shù)說明:
復(fù)制/src 源碼到新建文件夾 codec 并構(gòu)建新 Makefile:
codec
├── Makefile
└── src
├── sample.c
├── sample_common.c
├── sample.h
├── sample_vdec.c
└── sample_venc.c
Makefile:
CROSS_COMPILE = aarch64-none-linux-gnu-
OUTPUT_HBROOTFS_DIR = /usr/lib/sdk
CXX := ${CROSS_COMPILE}gcc
INC_DIR := ${OUTPUT_HBROOTFS_DIR}/usr/hobot/include
INC_DIR += ${OUTPUT_HBROOTFS_DIR}/include
LIB_DIR := ${OUTPUT_HBROOTFS_DIR}/usr/hobot/lib
LIB_DIR += ${OUTPUT_HBROOTFS_DIR}/usr/lib/aarch64-linux-gnu
LIBS += -lpthread -ldl -lhbmem -lalog -lmultimedia
LIBS += -lavformat -lavcodec -lavutil -lswresample
CXXFLAGS := -Wall -O2 $(foreach dir,$(INC_DIR),-I$(dir))
LDFLAGS := $(addprefix -L, $(LIB_DIR)) $(LIBS)
SRC_DIR := src
TARGET := program
SRCS := $(wildcard $(SRC_DIR)/*.c)
OBJS := $(SRCS:.c=.o)
$(TARGET): $(OBJS)
$(CXX) $(CXXFLAGS) $(LDFLAGS) $^ -o $@
%.o: %.c
$(CXX) $(CXXFLAGS) -c $< -o $@
clean:
rm -f $(OBJS) $(TARGET)
執(zhí)行 make 完成編譯,生成的文件為。/program
使用 WinScp 將 program 傳輸?shù)絾伟迳稀?需要 encode 的 yuv 文件請(qǐng)用戶自行準(zhǔn)備,本文檔使用 PYM 生成的 yuv 文件。
*WinScp 使用方法請(qǐng)參考征程 6E/M 底軟開發(fā) Sample-IPC 2.1.2
通過 ssh 或串口進(jìn)入/home/hobot/執(zhí)行:*w 和 h 需要進(jìn)行 16 字節(jié)對(duì)齊,如原始 yuv 不支持則會(huì)出現(xiàn)數(shù)據(jù)丟失
chmod +x program
#encode
#代碼可參考源碼目錄中的codec_sample.sh
./program -m 0 -c 3 -w 3840 -h 2160 -p 1 -i 3840x2160_pipe0_pym_ds0_f0_roi_1.yuv -o ./3840x2160.jpg
./program -m 0 -c 1 -w 3840 -h 2160 -p 1 -i 3840x2160_pipe0_pym_ds0_f0_roi_1.yuv -o ./3840x2160.h265
Sample 運(yùn)行時(shí)日志:
g_samplemode = 0
g_codecid = 3
g_width = 3840
g_height = 2160
g_pixfmt = 1
g_pixfmt = 1
g_inputfilename = 3840x2160_pipe0_pym_ds0_f0_roi_1.yuv
g_outputfilename = ./3840x2160.jpg
InputFileName = 3840x2160_pipe0_pym_ds0_f0_roi_1.yuv
OutputFileName = ./3840x2160.jpg
Thread use internal buffer mode, 0 rc mode
Failed to read input file (size=12441600)
There is no more input data(ret=0)!
There is no more output data!
生成的縮放 jpg 文件存放在指定-o 目錄下。
生成的 Jpeg 效果如下:
*有關(guān) jpg 工具查看 1080p 圖片時(shí)出現(xiàn)綠邊問題:
問題說明:這是因?yàn)楫?dāng)前 ip 進(jìn)行編碼時(shí)按照 16 位對(duì)齊進(jìn)行,假如到最后如果是 8 位對(duì)齊而不是 16 位對(duì)齊,那么編碼器就會(huì)在后面補(bǔ)齊,這部分補(bǔ)齊的數(shù)據(jù)是隨機(jī)產(chǎn)生的,不屬于有效數(shù)據(jù);
#decode
#使用上述生成的3840x2160.h265為例
./program -m 1 -c 1 -w 3840 -h 2160 -p 1 -i 3840x2160.h265 -o ./3840x2160.yuv
使用 YUView 打開生成的 3840x2160.yuv:
*注意配置 offset:
附件:
1、
*博客內(nèi)容為網(wǎng)友個(gè)人發(fā)布,僅代表博主個(gè)人觀點(diǎn),如有侵權(quán)請(qǐng)聯(lián)系工作人員刪除。