热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

针对androidiosyuv旋转、镜像、格式转换、裁剪算法实现

https:blog.csdn.netdangxw_articledetails50903693移动端录像在yuv数据上存在如下问题:1.无论android还是ios

https://blog.csdn.net/dangxw_/article/details/50903693


移动端录像在yuv数据上存在如下问题:

 

1.无论android还是ios都不能直接从摄像头取出颜色空间为i420的数据,所以在编码前需要进行格式转换。

2.而且由于所取图像得分辨率必须是摄像头所提供分辨率中得一组,所以有可能需要裁剪。

3.另外由于1)想让无论用户哪个方向拿手机所录的视频内容永远“头朝上”,

  2)摄像头默认返回图像为横屏图像(宽大于长)所以需要旋转。

4.前置摄像头需要镜像。

 

YUV 颜色空间分类:https://zh.wikipedia.org/wiki/YUV

 

yuv 420 又分为:

I420: YYYYYYYY UU VV   =>YUV420P
YV12: YYYYYYYY VV UU   =>YUV420P
NV12: YYYYYYYY UVUV    =>YUV420SP
NV21: YYYYYYYY VUVU    =>YUV420SP

 

下面给出解决这四个问题所需要得算法:

 

1 格式转换:

nv21 转成i420

 

[cpp] view plain copy
  1. //nv21 to yuvi420  
  2. void NV21ToI420(uint8_t* dstyuv,uint8_t* data, int imageWidth, int imageHeight)  
  3. {  
  4.     int Ustart =imageWidth*imageHeight;  
  5.     int i,j;  
  6.     int uWidth = imageWidth/2;  
  7.     int uHeight = imageWidth/2;  
  8.     //y  
  9.     memcpy(dstyuv,data,imageWidth*imageHeight);  
  10.     int tempindex = 0 ;  
  11.     int srcindex= 0;  
  12.     //u  
  13.     for(i= 0 ;i 
  14.     {  
  15.    
  16.    
  17.         for(j = 0;j 
  18.         {  
  19.             dstyuv[Ustart&#43;tempindex&#43;j]&#61; data[Ustart&#43;(srcindex<<1)&#43;1];  
  20.             srcindex&#43;&#43;;  
  21.         }  
  22.         tempindex&#43;&#61; uWidth;  
  23.     }  
  24.    
  25.    
  26.     //v  
  27.     for (i &#61; 0; i < uHeight;i&#43;&#43;)  
  28.     {  
  29.    
  30.         for (j &#61; 0; j < uWidth;j&#43;&#43;)  
  31.         {  
  32.             dstyuv[Ustart&#43;tempindex &#43; j] &#61; data[Ustart &#43; (srcindex << 1 )];  
  33.             srcindex&#43;&#43;;  
  34.         }  
  35.         tempindex&#43;&#61; uWidth;  
  36.     }  
  37. }  





 

其实就是改变了uv的位置。

 

2 裁剪&#xff1a;

[cpp] view plain copy
  1. //crop yuv data  
  2. int crop_yuv (char* data, char*dst, intwidth, intheight,  
  3.         int goalwidth, int goalheight) {  
  4.    
  5.     int i, j;  
  6.     int h_div &#61; 0, w_div &#61; 0;  
  7.     w_div&#61; (width - goalwidth) / 2;  
  8.     if (w_div % 2)  
  9.         w_div--;  
  10.     h_div&#61; (height - goalheight) / 2;  
  11.     if (h_div % 2)  
  12.         h_div--;  
  13.     //u_div &#61; (height-goalheight)/4;  
  14.     int src_y_length &#61; width *height;  
  15.     int dst_y_length &#61;goalwidth * goalheight;  
  16.     for (i &#61; 0; i 
  17.         for (j &#61; 0; j 
  18.             dst[i* goalwidth &#43; j] &#61; data[(i &#43; h_div) * width &#43; j &#43; w_div];  
  19.         }  
  20.     int index &#61; dst_y_length;  
  21.     int src_begin &#61;src_y_length &#43; h_div * width / 4;  
  22.     int src_u_length &#61;src_y_length / 4;  
  23.     int dst_u_length &#61;dst_y_length / 4;  
  24.     for (i &#61; 0; i 
  25.         for (j &#61; 0; j 
  26.             int p &#61; src_begin &#43; i *(width >> 1) &#43; (w_div >> 1) &#43; j;  
  27.             dst[index]&#61; data[p];  
  28.             dst[dst_u_length&#43; index&#43;&#43;] &#61; data[p &#43; src_u_length];  
  29.         }  
  30.    
  31.     return 0;  
  32. }  





 

 

3 旋转&#xff1a;

分为四个方向

 

 

 

旋转&#xff1a;

以顺时针旋转270度为例作图&#xff1a;

 

Y1

Y2

Y3

Y4

Y5

Y6

Y7

Y8

Y9

Y10

Y11

Y12

Y13

Y14

Y15

Y16

U1

U2

U3

U4

V1

V2

V3

V4

原图

 

 

 

Y4

Y8

Y12

Y16

Y3

Y7

Y11

Y15

Y2

Y6

Y10

Y14

Y1

Y5

Y9

Y13

U2

U4

U1

U3

V2

V4

V1

V3

旋转后

 

u值的第i 行j列 对应原 数据的下标为&#xff1a;  ustart&#43;uw*j-i;

去除index的乘除法运算后&#xff1a;

//i420 顺时针 270

[cpp] view plain copy
  1. int rotateYUV420Degree270(uint8_t* dstyuv,uint8_t* srcdata, int imageWidth, int imageHeight) {  
  2.    
  3.     int i &#61; 0, j &#61; 0;  
  4.    
  5.     int index &#61; 0;  
  6.     int tempindex &#61; 0;  
  7.     int div &#61; 0;  
  8.     for (i &#61; 0; i 
  9.         div&#61; i &#43;1;  
  10.         tempindex&#61; 0;  
  11.         for (j &#61; 0; j 
  12.    
  13.             tempindex&#43;&#61; imageWidth;  
  14.             dstyuv[index&#43;&#43;]&#61; srcdata[tempindex-div];  
  15.         }  
  16.     }  
  17.    
  18.     int start &#61;imageWidth*imageHeight;  
  19.     int udiv &#61; imageWidth *imageHeight / 4;  
  20.    
  21.     int uWidth &#61; imageWidth /2;  
  22.     int uHeight &#61; imageHeight /2;  
  23.     index&#61; start;  
  24.     for (i &#61; 0; i < uHeight;i&#43;&#43;) {  
  25.         div&#61; i &#43;1;  
  26.         tempindex&#61; start;  
  27.         for (j &#61; 0; j < uWidth;j&#43;&#43;) {  
  28.             tempindex &#43;&#61; uWidth;  
  29.             dstyuv[index]&#61; srcdata[tempindex-div];  
  30.             dstyuv[index&#43;udiv]&#61; srcdata[tempindex-div&#43;udiv];  
  31.             index&#43;&#43;;  
  32.         }  
  33.     }  
  34.    
  35.     return 0;  
  36.    
  37. }  





//i420 顺时针旋转 180&#xff1b;

[cpp] view plain copy
  1. int rotateYUV420Degree180(uint8_t* dstyuv,uint8_t* srcdata, int imageWidth, int imageHeight)  
  2. {  
  3.    
  4.     int i &#61; 0, j &#61; 0;  
  5.    
  6.     int index &#61; 0;  
  7.     int tempindex &#61; 0;  
  8.    
  9.     int ustart &#61; imageWidth *imageHeight;  
  10.     tempindex&#61; ustart;  
  11.     for (i &#61; 0; i 
  12.    
  13.         tempindex-&#61; imageWidth;  
  14.         for (j &#61; 0; j 
  15.    
  16.             dstyuv[index&#43;&#43;] &#61; srcdata[tempindex &#43; j];  
  17.         }  
  18.     }  
  19.    
  20.     int udiv &#61; imageWidth *imageHeight / 4;  
  21.    
  22.     int uWidth &#61; imageWidth /2;  
  23.     int uHeight &#61; imageHeight /2;  
  24.     index&#61; ustart;  
  25.     tempindex&#61; ustart&#43;udiv;  
  26.     for (i &#61; 0; i < uHeight;i&#43;&#43;) {  
  27.    
  28.         tempindex-&#61; uWidth;  
  29.         for (j &#61; 0; j < uWidth;j&#43;&#43;) {  
  30.    
  31.             dstyuv[index]&#61; srcdata[tempindex &#43; j];  
  32.             dstyuv[index&#43; udiv] &#61; srcdata[tempindex &#43; j &#43; udiv];  
  33.             index&#43;&#43;;  
  34.         }  
  35.     }  
  36.     return 0;  
  37. }  





 

 

顺时针 90度&#xff1a;

 

[cpp] view plain copy
  1. //i420顺时针旋转90 &#xff1b;  
  2. int rotateYUV420Degree90(uint8_t* dstyuv,uint8_t* srcdata, int imageWidth, int imageHeight) {  
  3.    
  4.     int i &#61; 0, j &#61; 0;  
  5.    
  6.     int index &#61; 0;  
  7.     int tempindex &#61; 0;  
  8.     int div &#61; 0;  
  9.     int ustart &#61; imageWidth *imageHeight;  
  10.     for (i &#61; 0; i 
  11.         div&#61; i;  
  12.         tempindex&#61; ustart;  
  13.         for (j &#61; 0; j 
  14.    
  15.             tempindex-&#61; imageWidth;  
  16.    
  17.             dstyuv[index&#43;&#43;]&#61; srcdata[tempindex &#43; div];  
  18.         }  
  19.     }  
  20.    
  21.    
  22.     int udiv &#61; imageWidth *imageHeight / 4;  
  23.    
  24.     int uWidth &#61; imageWidth /2;  
  25.     int uHeight &#61; imageHeight /2;  
  26.     index&#61; ustart;  
  27.     for (i &#61; 0; i < uHeight;i&#43;&#43;) {  
  28.         div&#61; i ;  
  29.         tempindex&#61; ustart&#43;udiv;  
  30.         for (j &#61; 0; j < uWidth;j&#43;&#43;) {  
  31.             tempindex-&#61; uWidth;  
  32.             dstyuv[index]&#61; srcdata[tempindex &#43; div];  
  33.             dstyuv[index&#43; udiv] &#61; srcdata[tempindex &#43; div &#43; udiv];  
  34.             index&#43;&#43;;  
  35.         }  
  36.     }  
  37.     return 0;  
  38.    
  39. }  



 

如果从摄像头取出数据&#xff0c;这样一步步的历遍&#xff0c;在低配手机上是满足不了需求的。其实这三个步骤中有很多中间步骤是可以省去的&#xff0c;比如&#xff1a;将a放到b 位置&#xff0c;再将b位置上的数据取出放到c位置&#xff0c;那么可以直接将a放到c位置。

所以需要优化以上三类问题所用的算法将其整合。结果如下&#xff1a;

 

[cpp] view plain copy
  1. void detailPic0(uint8_t* d, uint8_t* yuv_temp, int nw, int nh, int w, int h) {  
  2.     int deleteW &#61; (nw - w) / 2;  
  3.     int deleteH &#61; (nh - h) / 2;  
  4.     //处理y 旋转加裁剪  
  5.     int i, j;  
  6.     int index &#61; 0;  
  7.     for (j &#61; deleteH; j < nh- deleteH; j&#43;&#43;) {  
  8.         for (i &#61; deleteW; i < nw- deleteW; i&#43;&#43;)  
  9.             yuv_temp[index&#43;&#43;]&#61; d[j * nw &#43; i];  
  10.     }  
  11.    
  12.     //处理u  
  13.     index&#61; w * h;  
  14.    
  15.     for (i &#61; nh &#43; deleteH / 2;i < nh / 2 * 3 - deleteH / 2; i&#43;&#43;)  
  16.         for (j &#61; deleteW &#43; 1; j< nw - deleteW; j &#43;&#61; 2)  
  17.             yuv_temp[index&#43;&#43;]&#61; d[i * nw &#43; j];  
  18.    
  19.     //处理v 旋转裁剪加格式转换  
  20.     for (i &#61; nh &#43; deleteH / 2;i < nh / 2 * 3 - deleteH / 2; i&#43;&#43;)  
  21.         for (j &#61; deleteW; j < nw- deleteW; j &#43;&#61; 2)  
  22.             yuv_temp[index&#43;&#43;]&#61; d[i * nw &#43; j];  
  23.    
  24. }  



[cpp] view plain copy
  1. //针对横屏前摄像头 nv21 to 420sp  裁剪&#xff0c;旋转  
  2. void detailPic180(uint8_t* d, uint8_t* yuv_temp, int nw, int nh, int w, int h) {  
  3.     int deleteW &#61; (nw - w) / 2;  
  4.     int deleteH &#61; (nh - h) / 2;  
  5.     //处理y 旋转加裁剪  
  6.     int i, j;  
  7.     int index &#61; w * h;  
  8.     for (j &#61; deleteH; j < nh- deleteH; j&#43;&#43;) {  
  9.         for (i &#61; deleteW; i < nw- deleteW; i&#43;&#43;)  
  10.             yuv_temp[--index]&#61; d[j * nw &#43; i];  
  11.     }  
  12.    
  13.     //处理u  
  14.     index&#61; w * h * 5 / 4;  
  15.    
  16.     for (i &#61; nh &#43; deleteH / 2;i < nh / 2 * 3 - deleteH / 2; i&#43;&#43;)  
  17.         for (j &#61; deleteW &#43; 1; j< nw - deleteW; j &#43;&#61; 2)  
  18.             yuv_temp[--index]&#61; d[i * nw &#43; j];  
  19.    
  20.     //处理v 旋转裁剪加格式转换  
  21.     index&#61; w * h * 3 / 2;  
  22.     for (i &#61; nh &#43; deleteH / 2;i < nh / 2 * 3 - deleteH / 2; i&#43;&#43;)  
  23.         for (j &#61; deleteW; j < nw- deleteW; j &#43;&#61; 2)  
  24.             yuv_temp[--index]&#61; d[i * nw &#43; j];  
  25.    
  26. }  






[cpp] view plain copy
  1. void detailPic90(uint8_t* d, uint8_t* yuv_temp, int nw, int nh, int w, int h) {  
  2.    
  3.    
  4.    
  5.    
  6.    
  7.     int deleteW &#61; (nw - h) / 2;  
  8.     int deleteH &#61; (nh - w) / 2;  
  9.    
  10.     int i, j;  
  11.      }*/  
  12.     for (i &#61; 0; i < h; i&#43;&#43;){  
  13.         for (j &#61; 0; j < w; j&#43;&#43;){  
  14.             yuv_temp[(h- i) * w - 1 - j] &#61; d[nw * (deleteH &#43; j) &#43; nw - deleteW  
  15.                     -i];  
  16.         }  
  17.     }  
  18.    
  19.     int index &#61; w * h;  
  20.     for (i &#61; deleteW &#43; 1; i< nw - deleteW; i &#43;&#61; 2)  
  21.         for (j &#61; nh / 2 * 3 -deleteH / 2; j > nh &#43; deleteH / 2; j--)  
  22.             yuv_temp[index&#43;&#43;]&#61; d[(j - 1) * nw &#43; i];  
  23.    
  24.     for (i &#61; deleteW; i < nw- deleteW; i &#43;&#61; 2)  
  25.         for (j &#61; nh / 2 * 3 -deleteH / 2; j > nh &#43; deleteH / 2; j--)  
  26.             yuv_temp[index&#43;&#43;]&#61; d[(j - 1) * nw &#43; i];  
  27.    
  28. }  
  29.    





[cpp] view plain copy
  1. void detailPic270(uint8_t* d, uint8_t* yuv_temp, int nw, int nh, int w, int h) {  
  2.     int deleteW &#61; (nw - h) / 2;  
  3.     int deleteH &#61; (nh - w) / 2;  
  4.     int i, j;  
  5.     //处理y 旋转加裁剪  
  6.     for (i &#61; 0; i < h; i&#43;&#43;){  
  7.         for (j &#61; 0; j < w; j&#43;&#43;){  
  8.             yuv_temp[i* w &#43; j] &#61; d[nw * (deleteH &#43; j) &#43; nw - deleteW - i];  
  9.         }  
  10.     }  
  11.    
  12.     //处理u 旋转裁剪加格式转换  
  13.     int index &#61; w * h;  
  14.     for (i &#61; nw - deleteW - 1;i > deleteW; i -&#61; 2)  
  15.         for (j &#61; nh &#43; deleteH / 2;j < nh / 2 * 3 - deleteH / 2; j&#43;&#43;)  
  16.             yuv_temp[index&#43;&#43;]&#61; d[(j) * nw &#43; i];  
  17.    
  18.     //处理v 旋转裁剪加格式转换  
  19.    
  20.     for (i &#61; nw - deleteW - 2;i >&#61; deleteW; i -&#61; 2)  
  21.         for (j &#61; nh &#43; deleteH / 2;j < nh / 2 * 3 - deleteH / 2; j&#43;&#43;)  
  22.             yuv_temp[index&#43;&#43;]&#61; d[(j) * nw &#43; i];  
  23.    
  24. }  
  25.    





 

注&#xff1a;没有优化&#xff0c;消除index的乘法后效果肯定会更好。

 

4 镜像&#xff1a;

 

[cpp] view plain copy
  1. //mirro 原址的  
  2. void Mirror(uint8_t* yuv_temp, int nw, int nh, int w,  
  3.         int h) {  
  4.     int deleteW &#61; (nw - h) / 2;  
  5.     int deleteH &#61; (nh - w) / 2;  
  6.     int i, j;  
  7.      
  8.     int a, b;  
  9.     uint8_ttemp;  
  10.     //mirror y  
  11.     for (i &#61; 0; i < h; i&#43;&#43;){  
  12.         a&#61; i * w;  
  13.         b&#61; (i &#43; 1) * w - 1;  
  14.         while (a < b) {  
  15.             temp&#61; yuv_temp[a];  
  16.             yuv_temp[a]&#61; yuv_temp[b];  
  17.             yuv_temp[b]&#61; temp;  
  18.             a&#43;&#43;;  
  19.             b--;  
  20.         }  
  21.     }  
  22.     //mirror u  
  23.     int uindex &#61; w * h;  
  24.     for (i &#61; 0; i < h / 2;i&#43;&#43;) {  
  25.         a &#61; i * w / 2;  
  26.         b&#61; (i &#43; 1) * w / 2 - 1;  
  27.         while (a < b) {  
  28.             temp&#61; yuv_temp[a &#43; uindex];  
  29.             yuv_temp[a&#43; uindex] &#61; yuv_temp[b &#43; uindex];  
  30.             yuv_temp[b&#43; uindex] &#61; temp;  
  31.             a&#43;&#43;;  
  32.             b--;  
  33.         }  
  34.     }  
  35.     //mirror v  
  36.     uindex&#61; w * h / 4 * 5;  
  37.     for (i &#61; 0; i < h / 2;i&#43;&#43;) {  
  38.         a&#61; i * w / 2;  
  39.         b&#61; (i &#43; 1) * w / 2 - 1;  
  40.         while (a < b) {  
  41.             temp&#61; yuv_temp[a &#43; uindex];  
  42.             yuv_temp[a&#43; uindex] &#61; yuv_temp[b &#43; uindex];  
  43.             yuv_temp[b&#43; uindex] &#61; temp;  
  44.             a&#43;&#43;;  
  45.             b--;  
  46.         }  
  47.     }  
  48.    
  49. }  





 

 

由于当初忽略了镜像&#xff0c;所以并没有把镜像也和其他三个算法和并到一起。不过测试还是通过的。

 

如果集成ffmpeg或者opencv&#xff0c;可以使用ffmpeg的sws&#xff0c;filter 或者opencv的cvtcolor都可以轻松实现部分功能&#xff0c;不过跟踪过ffmpeg sws的源码&#xff0c;发现效率较低&#xff0c;代码实现较差。如果追求处理效率&#xff0c;并且以上优化的算法仍不能满足&#xff0c;建议使用libyuv&#xff0c;其中试用了很多汇编指令加速&#xff0c;效率惊人。



推荐阅读
  • 开机自启动的几种方式
    0x01快速自启动目录快速启动目录自启动方式源于Windows中的一个目录,这个目录一般叫启动或者Startup。位于该目录下的PE文件会在开机后进行自启动 ... [详细]
  • 三角测量计算三维坐标的代码_双目三维重建——层次化重建思考
    双目三维重建——层次化重建思考FesianXu2020.7.22atANTFINANCIALintern前言本文是笔者阅读[1]第10章内容的笔记,本文从宏观的角度阐 ... [详细]
  • Halcon之图像梯度、图像边缘、USM锐化
    图像梯度、图像边缘、USM锐化图像梯度、图像边缘、USM锐化图像梯度、图像边缘、USM锐化图像卷积:1.模糊2.梯度3.边缘4.锐化1.视频教程:B站、 ... [详细]
  • 解决Bootstrap DataTable Ajax请求重复问题
    在最近的一个项目中,我们使用了JQuery DataTable进行数据展示,虽然使用起来非常方便,但在测试过程中发现了一个问题:当查询条件改变时,有时查询结果的数据不正确。通过FireBug调试发现,点击搜索按钮时,会发送两次Ajax请求,一次是原条件的请求,一次是新条件的请求。 ... [详细]
  • 本文详细探讨了Oracle数据库中Number和Float数据类型的特性和使用方法。通过对比分析,解释了Number类型在精度和范围上的优势,以及Float类型在处理科学计算时的灵活性。文章还介绍了Number数据类型的语法结构及其在实际应用中的最佳实践,帮助读者更好地理解和选择合适的数据类型以满足不同的业务需求。 ... [详细]
  • 在Linux系统中,网络配置是至关重要的任务之一。本文详细解析了Firewalld和Netfilter机制,并探讨了iptables的应用。通过使用`ip addr show`命令来查看网卡IP地址(需要安装`iproute`包),当网卡未分配IP地址或处于关闭状态时,可以通过`ip link set`命令进行配置和激活。此外,文章还介绍了如何利用Firewalld和iptables实现网络流量控制和安全策略管理,为系统管理员提供了实用的操作指南。 ... [详细]
  • PHP预处理常量详解:如何定义与使用常量 ... [详细]
  • 本文详细介绍了在 CentOS 7 系统中配置 fstab 文件以实现开机自动挂载 NFS 共享目录的方法,并解决了常见的配置失败问题。 ... [详细]
  • Python 数据可视化实战指南
    本文详细介绍如何使用 Python 进行数据可视化,涵盖从环境搭建到具体实例的全过程。 ... [详细]
  • 本文对比了杜甫《喜晴》的两种英文翻译版本:a. Pleased with Sunny Weather 和 b. Rejoicing in Clearing Weather。a 版由 alexcwlin 翻译并经 Adam Lam 编辑,b 版则由哈佛大学的宇文所安教授 (Prof. Stephen Owen) 翻译。 ... [详细]
  • 本文详细介绍了 PHP 中对象的生命周期、内存管理和魔术方法的使用,包括对象的自动销毁、析构函数的作用以及各种魔术方法的具体应用场景。 ... [详细]
  • 本文详细介绍了MySQL数据库的基础语法与核心操作,涵盖从基础概念到具体应用的多个方面。首先,文章从基础知识入手,逐步深入到创建和修改数据表的操作。接着,详细讲解了如何进行数据的插入、更新与删除。在查询部分,不仅介绍了DISTINCT和LIMIT的使用方法,还探讨了排序、过滤和通配符的应用。此外,文章还涵盖了计算字段以及多种函数的使用,包括文本处理、日期和时间处理及数值处理等。通过这些内容,读者可以全面掌握MySQL数据库的核心操作技巧。 ... [详细]
  • 本文介绍了如何利用 `matplotlib` 库中的 `FuncAnimation` 类将 Python 中的动态图像保存为视频文件。通过详细解释 `FuncAnimation` 类的参数和方法,文章提供了多种实用技巧,帮助用户高效地生成高质量的动态图像视频。此外,还探讨了不同视频编码器的选择及其对输出文件质量的影响,为读者提供了全面的技术指导。 ... [详细]
  • 在软件开发过程中,经常需要将多个项目或模块进行集成和调试,尤其是当项目依赖于第三方开源库(如Cordova、CocoaPods)时。本文介绍了如何在Xcode中高效地进行多项目联合调试,分享了一些实用的技巧和最佳实践,帮助开发者解决常见的调试难题,提高开发效率。 ... [详细]
  • Android 构建基础流程详解
    Android 构建基础流程详解 ... [详细]
author-avatar
万宝盛华猎头
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有