已阅读5页,还剩69页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
第2章 WAV文件格式 第2章 WAV文件格式 2.1 WAV文件格式1,2,3,4 2.2 保存为WAV文件格式1,2,3,4,5 2.3 压缩WAVE音频5 2.4 本 章 小 结 第2章 WAV文件格式 2.1 WAV文件格式1,2,3,4 2.1.1 RIFF文件和WAV文件格式 1RIFF文件 RIFF可以看做是一种树状结构,其基本构成单位为“ 块”(Chunk),它犹如树状结构中的节点。每个 Chunk由“辨别码”(ID)、“数据大小”(Size)和“数据 ”(Data)所组成,如表2-1所示。 第2章 WAV文件格式 表2-1 RIFF文件格式 辨别码 (ID) 用4字符(ASCII码)表示 用于表示Chunk“数据”的类型。如果一个应用程序不能识别该“辨别码”, 则将忽略由Chunk“大小”所指定的Chunk “数据”和附加的数据 数据大小 (Size) 用32位无符号数值表示 用于表示Chunk“数据”的长度和Chunk “数据”后附加的数据长度(单位为 Byte),这一值还包括Chunk“辨别码”和Chunk “大小”所占用的空间(共 8 Byte) 数据 (Data) 二进制数据,数据可以是固定长度也可以是可变长度。相对于RIFF文件起 始位置,数据是“字对齐”(Word-aligned)的,这样可以提高数据访问速度 。如果数据的字节长度为奇数,那么在数据后面要附加一个字节,以保持“ 字对齐” 第2章 WAV文件格式 一般而言,Chunk本身并不允许内部再包含Chunk, 但有两种情况例外,即分别以“RIFF”及“LIST”为辨别 码的Chunk可以包含子Chunk。 以“RIFF”为辨别码的Chunk包含子Chunk的格式如图 2-1所示。图中前4个字符 第2章 WAV文件格式 图2-1 RIFF文件结构 第2章 WAV文件格式 2WAV文件 WAV为WAVEFORM(波形)的缩写。WAV文件的 结构如图2-2所示,RIFF Chunk中子Chunk的“格式辨别 码”为“WAVE”。整个文件由两个Chunk所组成:辨别 码“fmt”(注意,最后一个是空白字符)及“data”。 第2章 WAV文件格式 图2-2 WAV文件结构 第2章 WAV文件格式 在“fmt”的Chunk下包含了一个PCMWAVEFORMAT 数据结构,该结构与前一章中的WAVEFORMATEX结 构类似,其定义如下: typedef struct waveformat - tag WORDwFormatTag ; WORD nChannels; DWORDnSamplesPerSec; DWORD nAvgBytesperSec; WORDnBlockAlign; WAVEFORMAT; 第2章 WAV文件格式 typedef struct pcmwaveformat - tag WAVEFORMAT wf ; WORD wBitsPerSample; PCMWAVEFORMAT; 第2章 WAV文件格式 其意义分别如下: wFormatTag:记录着此声音的格式代号,例如 WAVE_FORMAT_PCM,WAVE_FORMAT_ADPCM 等等。 nChannels:记录声音的声道数。 nSamp1esPerSec:记录每秒采样数(采样率)。 nAvgBytesPerSec:记录每秒的平均数据量。 nBlockA1ign:记录块的对齐单位。 wBitsPerSample:记录每个采样样本所需的位元数。 第2章 WAV文件格式 “data”Chunk包含真正的声音数据。Windows目前仅提 供WAVE_FORMAT_PCM一种数据格式,其所代表的 意义是脉冲编码调制(PCM,Pu1se Code Modulation )。 用编辑工具UltraEdit查看WAV文件的文件头,如图2 -3所示。 表2-2以数据在文件中的存放位置说明了WAV文件格 式,其中偏移地址是相对于文件头的地址。 第2章 WAV文件格式 图2-3 WAV文件的文件头 第2章 WAV文件格式 表2-2 WAV文件格式说明表 偏移地址字节数数据类型内 容 说 明 00H4Char “RIFF”标志 04H4Long文件长度 08H4Char “WAVE”标志 0CH4Char “fmt”标志 10H4LongWAVEFORMAT结构的长度 14H2Int格式类别(例如,10H为PCM形式的声音数据) 16H2Int声道数,单声道为1,双声道为2 18H4Long采样率(每秒样本数),表示每个声道的播放速度 1CH4long int波形音频数据传送速率,其值为(声道数每秒数据位数每样 本的数据位数)/8。播放软件利用此值可以估计缓冲区的大小 第2章 WAV文件格式 偏移地 址 字节数数据类型内 容 说 明 20H2Int 数据块的调整数(按字节算的),其值为(声道数每样本 的数据位数)/8。播放软件需要一次处理多个该值大小的字 节数据,以便将其值用于缓冲区的调整 22H2Int 每样本的数据位数,表示每个声道中各个样本的数据位数 。如果有多个声道,对每个声道而言,样本大小都一样 24H4Char数据标记符“data” 28H4long int声音数据的长度 28H以后 long int声音数据 第2章 WAV文件格式 Windows定义了在“data”Chunk中数据的存放情形, 表2-3列出了四种不同声道数及取样所需的位元数以及 位元位置的安排。其中: 对于8位单声道,每个样本数据由8位(bit)表示; 对于8位立体声,每个声道的数据由一个8位(bit)数据 表示,且第一个8位(bit)数据表示0声道(左)数据 ,紧随其后的8位(bit)数据表示1声道(右)数据; 对于16位单声道,每个样本数据由16位(bit)表示; 第2章 WAV文件格式 对于16位立体声,每个声道的数据由一个16位(bit )数据表示,且第一个16位(bit)数据表示0声道(左 )数据,紧随其后的16位(bit)数据表示1声道(右) 数据。 第2章 WAV文件格式 表2-3 PCM数据的存放方式 样本1 (1 Byte)样本2(1 Byte)样本3(1 Byte)样本4(1 Byte) 8位单声道0声道0声道0声道0声道 8位立体声0声道(左)1声道(右)0声道(左)1声道(右) 样本1(2 Byte)样本2(2 Byte) 16位单声道0声道低字节0声道高字节0声道低字节0声道高字节 16位立体声0声道(左)低字节0声道(左)高字节1声道(右)低字节1声道(右)高字节 第2章 WAV文件格式 WAV文件的每个样本值包含在一个整数i中,i的长 度为容纳指定样本长度所需的最小字节数。首先存储 低有效字节,表示样本幅度的位放在i的高有效位上, 剩下的位置为0,这样8位和16位的PCM波形样本的数 据格式如表2-4所示。 第2章 WAV文件格式 表2-4 PCM数据的存放方式 样本大小数据格式最大值最小值静 音 8位PCMunsigned int2250128 16位PCMint32 767-32 7670 第2章 WAV文件格式 2.1.2 WAV文件信息的具体应用 WAV文件包括了对原始声音的高速率采样数据,并 且以WAVE_PCM_FORMAT格式的形式保存。在读出 WAV文件头信息之后,接着的数据就是原始声音的高 速率采样信息。我们可以在Visual C+程序中对这些信 息作多方面的处理,其中包括: 第2章 WAV文件格式 波形显示 我们可以以时间振幅的方式显示出原始声音的波形 ,这是最简单同时也是最直接的信息处理方式。在时 间范围内,我们可以观察该信号波形是否连续,中间 是否有跳变等。 频谱显示 我们可以以频率振幅的方式显示出原始声音的频 谱,在对原始信号经过FFT变换之后,可以得到该信号 的频谱,进而得到该信号的能量集中带、分布特征、 谱对称系数等等。 第2章 WAV文件格式 用于语音信号识别 讲话者的个体识别是语音信号处理的一个重要内容 ,但它的一个前提条件是必须提供语音信号的数字波形 。通常的方法是将原始的语音信号进行放大、抗混叠滤 波、A/D采样、数值编码,最终得到语音信号的数字波形 。 第2章 WAV文件格式 2.2 保存为WAV文件格式1,2,3,4,5 2.2.1 创建一个空文件 用系统函数CreateFile创建一个空文件,其程序如下: #include FILE* m_fp = NULL;/文件句柄 DWORDdwFileSize=0; /文件长度 第2章 WAV文件格式 DWORD dwTotalAudioLength=0;/声音数据长度 HANDLEOpenFileToWrite(LPCTSTR lpFileName) SECURITY_ATTRIBUTESsa; sa.nLength = sizeof(SECURITY_ATTRIBUTES); sa.lpSecurityDescriptor = NULL; sa.bInheritHandle = FALSE; return CreateFile(lpFileName, GENERIC_WRITE, 0, 第2章 WAV文件格式 2.2.2 写WAV文件头 首先,要得到声音采样数据的相关信息,通常这些 信息存储在一个WAVEFORMATEX结构中,用系统函 数WriteFile将文件头信息写入新创建的文件。其程序 如下: BOOL WriteWaveFileHeader(char *DesFilename, WAVEFORMATEX wfx) long cbFmtChunk, cbDataChunk; 第2章 WAV文件格式 /m_fp在前面已定义过 m_fp = fopen ( DesFilename , “w+b“ ); if (!m_fp ) return FALSE; /打开文件出错 cbFmtChunk = sizeof(WAVEFORMATEX) +wfx.cbSize; /WAVEFORMATEX结构长度 dwFileSize= 46;/46为文件头的长度 dwTotalAudioLength=0; cbDataChunk = dwTotalAudioLength; 第2章 WAV文件格式 fwrite ( “RIFF“,1, sizeof (DWORD), m_fp ); /RIFF标识 符(占用4 Byte) fwrite ( /文件长度(占用4 Byte) fwrite ( “WAVE“,1, sizeof (DWORD), m_fp ); /WAVE标识符(占用4 Byte) fwrite ( “fmt “,1, sizeof (DWORD), m_fp ); /fmt标识符(占用4 Byte) fwrite ( /WAVEFORMAT结构的长度(4 Byte) 第2章 WAV文件格式 fwrite ( /WAVEFORMAT结构的内容 (18 Byte) fwrite ( “data“,1, sizeof (DWORD), m_fp ); /data标识符(占用4 Byte) fwrite ( /声音数 据长度(占用4 Byte) return TRUE; 第2章 WAV文件格式 2.2.3 写声音数据 将给定缓冲区中声音数据写入WAV文件,其程序 如下: BOOL WriteWaveFileData(LPBYTE lpBufferData, DWORD dwDataSize) if (dwDataSize = 0) 第2章 WAV文件格式 return FALSE; else fwrite(lpBufferData, 1, dwDataSize, m_fp); dwFileSize+= dwDataSize; /文件长度随着增加 dwTotalAudioLength=dwTotalAudioLength+ dwDataSize;/声音数据长度随着增加 return TRUE; 第2章 WAV文件格式 fseek( m_fp, 42, SEEK_SET ); /设置文件指针 fwrite(/写入声音数据长度 fclose(m_fp); /关闭文件 m_fp = NULL; return true; 第2章 WAV文件格式 2.3 压缩WAVE音频5 2.3.1 CODECs介绍 Microsoft的Windows 95/98/NT/2000操作系统都具有 能通过安装的CODECs处理编码的WAVE格式的音频 和视频数据流的能力。 一个CODEC是一小段用于编码(Code)及解码( DECode)数据流的代码(因此得名CODEC)。许多 CODECs既能编码又能解码。而一些CODECs仅能用于 解码,这样私有数据可以在系统上播放,但数据格式 不能在系统上创建。 第2章 WAV文件格式 2.3.2 系统中有什么CODECs Microsoft的Windows 95/98/NT/2000本身附带有几 种标准的CODECs,也可由系统中所安装的应用程序 安装其它的 CODECs。例如,DSP Group公司的 TrueSpeech CODEC随Windows 95发送,因此,用户写 的任何基于Windows 95的应用程序都可使用此CODEC (只要用户没有在控制面板中删除它或禁止它)。 第2章 WAV文件格式 所有安装的CODECs都由音频编码解码器(ACM) 管理(见图2-4)。我们可以用一段小程序从ACM中查 到安装了哪些CODECs,它们都支持什么格式。也可 双击控制面板中的多媒体选项,选择高级标签,就能 看到系统中所安装的CODECs。 下面用一段程序介绍如何应用ACM。首先从调用 ACM编程接口所需的包含的头文件开始: 第2章 WAV文件格式 #include #include #include / 多媒体注册 #include / 音频编码解码器 #include 第2章 WAV文件格式 图2-4 音频编码解码器 第2章 WAV文件格式 mmsystem.h头文件包含了Windows支持的大部分的 多媒体功能,但不包含ACM接口及任何厂商定义。 mmreg.h包含了对不同厂商设计的各种WAVE数据类 型的格式标签的定义。它也包含了用于处理不同的 WAVE数据类型的结构(基于WAVEFORAMTEX)的 定义。 msacm.h包含了ACM所需的API、标志等等。 我们要做的第一件事就是执行一些常见的ACM查询 来判断版本号,获取它当前管理了多少个驱动程序的 信息。下面是查询ACM的部分代码: 第2章 WAV文件格式 DWORD dwACMVer = acmGetVersion( ); printf(“ACM version %u.%.02u build %u“, HIWORD(dwACMVer) 8, HIWORD(dwACMVer) if (LOWORD(dwACMVer) = 0) printf(“ (Retail)“); printf(“n“); 第2章 WAV文件格式 acmGetVersion函数返回一个32位的十六进制数值, 表示ACM的版本号,其形如0xAABBCCCC。其中, AA代表ACM的主版本号;BB代表ACM的副版本号; CCCC代表ACM的debug版本的build号,对于一个非 debug版本(零售版)的ACM,CCCC总为0。例如, 在应用程序中返回版本号为0x05000856,则ACM版本 号为5.00,且系统中安装的是debug版本,build号为 2134(十进制)。 第2章 WAV文件格式 用acmMetrics函数可以知道系统中安装了多少个 CODECs驱动程序: DWORD dwCodecs = 0; MMRESULTmmr=acmMetrics(NULL, ACM_METRIC_COUNT_CODECS, if (mmr) /show_error(mmr); else printf(“%lu codecs installedn“, dwCodecs); 第2章 WAV文件格式 对ACM有了简单了解后,现在可以要求它枚举出系 统中当前所有的驱动程序。我们在程序中所调用的枚 举函数使用回调函数来显示每个设备的数据,这在 Windows编程中是一种很普遍的方法。下面的调用就 是枚举当前ACM所管理的所有设备: / 枚举所有允许的驱动程序 printf(“Enabled drivers:n“); mmr = acmDriverEnum(DriverEnumProc, 0, 0); if (mmr) /show_error(mmr); 第2章 WAV文件格式 acmDriverEnum函数列举出可用的ACM驱动程序, 第一个参数指出回调函数的地址。现在,让我们看看 枚举回调函数DriverEnumProc,它由系统中的每一个 驱动程序调用: BOOL CALLBACK DriverEnumProc(HACMDRIVERID hadid, DWORD dwInstance, DWORD fdwSupport) printf(“ id: %8.8lxH“, hadid); printf(“ supports:n“); 第2章 WAV文件格式 if(fdwSupport if(fdwSupport if(fdwSupport if(fdwSupport 第2章 WAV文件格式 / 获得一些具体信息 ACMDRIVERDETAILS dd; dd.cbStruct = sizeof(dd); MMRESULT mmr = acmDriverDetails(hadid, if (mmr) printf(“ “); /show_error(mmr); else 第2章 WAV文件格式 printf(“ Short name: %sn“, dd.szShortName); printf(“ Long name: %sn“, dd.szLongName); printf(“ Copyright: %sn“, dd.szCopyright); printf(“ Licensing: %sn“, dd.szLicensing); printf(“ Features: %sn“, dd.szFeatures); printf(“ Supports %u formatsn“, dd.cFormatTags); printf(“ Supports %u filter formatsn“, dd.cFilterTags); 第2章 WAV文件格式 / 打开驱动程序 HACMDRIVER had = NULL; mmr = acmDriverOpen( if (mmr) printf(“ “); /show_error(mmr); else DWORD dwSize = 0; 第2章 WAV文件格式 mmr = acmMetrics(had, ACM_METRIC_MAX_SIZE_FORMAT, if(dwSizecbSize=LOWORD(dwSize) sizeof(WAVEFORMATEX); pwf-wFormatTag = WAVE_FORMAT_UNKNOWN; ACMFORMATDETAILS fd; memset( fd.cbStruct = sizeof(fd); fd.pwfx = pwf; fd.cbwfx = dwSize; fd.dwFormatTag = WAVE_FORMAT_UNKNOWN; mmr = acmFormatEnum(had, 第2章 WAV文件格式 if (mmr) printf(“ “); /show_error(mmr); free(pwf); acmDriverClose(had, 0); return TRUE; / 继续枚举 第2章 WAV文件格式 为结构分配了空间后,现在可以用acmFormatEnum来 枚举所支持的格式。这次又用到一个回调函数来取得 枚举出的所支持格式的相关数据: BOOL CALLBACK FormatEnumProc(HACMDRIVERID hadid, LPACMFORMATDETAILS pafd, DWORD dwInstance, DWORD fdwSupport) printf(“ %4.4lXH, %sn“, pafd-dwFormatTag, pafd-szFormat); return TRUE; / 继续枚举 第2章 WAV文件格式 2.3.3 使用特定的CODEC 1两步实现编码 在理想的情况下,编码一些数据可能只要向系统 发出命令“这有一些数据,请编码成这种格式”即可。 但实际上,Windows编程与理想相去甚远,在当前的 现实中,我们得自已做许多琐碎的工作。 第2章 WAV文件格式 2编码的实现过程 在本例中,实现编码分以下四个阶段: (1) 创建一些WAV格式数据的样本; (2) 找到一个合适的CODEC; (3) 将数据转换为该CODEC可处理的中间格式; (4) 将数据转换成所需的格式。 第2章 WAV文件格式 为了简单起见,源数据用程序创建,而不是录入或是从 WAV文件中读取: / 首先我们创建一个可能是刚刚才录制的WAV,其格式 为11.025 kHz, 8位单声道PCM,这是一个 / 在所有机器上都可用的录入格式。例如1秒长的1 kHz的 正弦波WAVE,刚好1000个周期 WAVEFORMATEX wfSrc; memset( wfSrc.cbSize = 0; 第2章 WAV文件格式 wfSrc.wFormatTag = WAVE_FORMAT_PCM; / PCM wfSrc.nChannels = 1; / 单声道 wfSrc.nSamplesPerSec = 11025; / 11.025 kHz wfSrc.wBitsPerSample = 8; / 8 bit wfSrc.nBlockAlign = wfSrc.nChannels * wfSrc.wBitsPerSample / 8; wfSrc.nAvgBytesPerSec = wfSrc.nSamplesPerSec * wfSrc.nBlockAlign; DWORD dwSrcSamples = wfSrc.nSamplesPerSec; 第2章 WAV文件格式 BYTE* pSrcData = new BYTE dwSrcSamples; / 分配1 秒种的长度内存空间 BYTE* pData = pSrcData; double f = 1000.0; double pi = 4.0 * atan(1.0); double w = 2.0 * pi * f; for (DWORD dw = 0; dw wBitsPerSample, pwfDrv-nSamplesPerSec); / 获取驱动程序所支持的PCM格式标签 / 注意:我们只是选取CODEC所支持的枚举出的第一 种PCM格式,但不一定是最好的选择 WAVEFORMATEX* pwfPCM = get_driver_format(hadid, WAVE_FORMAT_PCM); if (pwfPCM = NULL) printf(“Error getting PCM format infon“); exit(1); 第2章 WAV文件格式 printf(“PCM format: %u bits, %lu samples per secondn“, pwfPCM-wBitsPerSample, pwfPCM-nSamplesPerSec); 还要进一步强调的是,get_driver_format函数仅仅枚举出 第一种匹配的格式,也许不能获得最好的质量。 第2章 WAV文件格式 让我们看看第一步的转换,它完成的是将源数据转 换为中间格式: / 将源WAVE转换为CODEC所支持的PCM格式 / 我们使用任一种能实现PCM格式间相互转换的驱动 程序 HACMSTREAM hstr = NULL; mmr = acmStreamOpen( / 标志 第2章 WAV文件格式 if (mmr) printf(“Failed to open a stream to do PCM to PCM conversionn“); exit(1); / 为转换结果开辟一个缓冲区 DWORD dwSrcBytes = dwSrcSamples * wfSrc.wBitsPerSample / 8; DWORD dwDst1Samples =dwSrcSamples * pwfPCM- nSamplesPerSec / wfSrc.nSamplesPerSec; DWORD dwDst1Bytes = dwDst1Samples * pwfPCM- wBitsPerSample / 8; 第2章 WAV文件格式 BYTE* pDst1Data = new BYTE dwDst1Bytes; / 填写转换信息 ACMSTREAMHEADER strhdr; memset( strhdr.cbStruct = sizeof(strhdr); strhdr.pbSrc = pSrcData; / 要转换的源数据 strhdr.cbSrcLength = dwSrcBytes; strhdr.pbDst = pDst1Data; strhdr.cbDstLength = dwDst1Bytes; / 准备好头 mmr = acmStreamPrepareHeader(hstr, / 转换数据 第2章 WAV文件格式 printf(“Converting to intermediate PCM format.n“); mmr = acmStreamConvert(hstr, if (mmr) printf(“Failed to do PCM to PCM conversionn“); exit(1); printf(“Converted OKn“); / 关闭流 acmStreamClose(hstr, 0); 第2章 WAV文件格式 最后一步是将中间格式转换为最终的压缩格式: / 将中间格式转换为最终的压缩格式 / 打开驱动程序 HACMDRIVER had = NULL; mmr = acmDriverOpen( if (mmr) printf(“Failed to open drivern“); exit(1); 第2章 WAV文件格式 / 打开转换流 / 注意使用了ACM_STREAMOPENF_NONREALTIME标志 / 若没有此标志,一些软件压缩程序会报告512号错误,即不可能 mmr = acmStreamOpen( exit(1); / 为转换结果分配一个缓冲区 / 根据以字节计的平均速率计算输出缓冲区的尺寸 / 并加上一机动位(bit) 第2章 WAV文件格式 / 若没有此额外的空间,IMA_ADPCM驱动程序将不能转换 DWORD dwDst2Bytes=pwfDrv-nAvgBytesPerSec *dwDst1Samples/ pwfPCM-nSamplesPerSec; dwDst2Bytes = dwDst2Bytes * 3 / 2;/ 增加一 点空间 BYTE* pDst2Data = new BYTE dwDst2Bytes; / 填写
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2025年政工师考试试题含答案
- 安全风险分级管控和隐患排查治理双重预防工作机制试题及答案
- 2025年全国工业锅炉G1证理论考试题库含答案
- 2025年新媒体运营专业考核试卷及答案
- 社区公共安全突发事件应急预案
- 必修16 用牛顿定律解决问题(一)教案设计
- 儒释道思想对文学创作的影响研究
- 护理三基理论考试试题附答案
- 2025三基三严护理理论考试试题及答案
- 2025年医院三基考试医师模拟试题(含答案)
- 手术器械清洗与维护
- 大学生职业生涯规划书成长赛道模板
- DL-光伏发电站电能质量检测技术规程
- 2023版《思想道德与法治》(绪论-第一章)绪论 担当复兴大任 成就时代新人;第一章 领悟人生真谛 把握人生方向 第3讲 创造有意义的人生
- 加利福尼亚批判性思维技能测试后测试卷班附有答案
- 宏观经济学(河海大学)智慧树知到期末考试答案2024年
- 新国际政治学概论(第三版)-教学课件-陈岳-109503国际政治学概论(第三版)
- 坚持以人民为中心
- 小学二年级数学奥数植树问题(锯木头剪绳子)课件
- 口腔颌面外科学导论
- 贾惜春语文用
评论
0/150
提交评论