登录 用户中心() [退出] 后台管理 注册
   
您的位置: 首页 >> 程序员学前班[不再更新,只读] >> 主题: xvid静态库的封装类(编码和解码)     [回主站]     [分站链接]
标题
xvid静态库的封装类(编码和解码)
clq
浏览(1) + 2010-08-19 09:22:00 发表 编辑

关键字:

http://blog.chinaunix.net/u/26691/showart_330239.html

其中 xvidcore.dll 不需要自己编译,直接安装一个 XviD_1.2.2_EN.exe 就有了,然后按照如下方式生成 lib .

--------------------------------------------------
DUMPBIN xvidcore.dll /EXPORTS /OUT:xvidcore.def

对 def 进行修改后得到

--------------------------------------------------

LIBRARY   "xvidcore"
    DESCRIPTION   "xvidcore library"

    EXPORTS
       
xvid_decore                     @1
xvid_encore                     @2
xvid_global                     @3
xvid_plugin_2pass1              @4      
xvid_plugin_2pass2              @5      
xvid_plugin_dump                @6   
xvid_plugin_lumimasking         @7         
xvid_plugin_psnr                @8   
xvid_plugin_single              @9     
xvid_plugin_ssim                @10  
--------------------------------------------------
再调用 LIB /DEF:1.def /MACHINE:IX86 即可.

DUMPBIN 和 LIB 都是 vc 的工具,好象 vc6 和 vs2008 下都有. 头文件从 xvid 源码复制就行了,只需要 xvid.h

clq
2010-8-19 9:24:03 发表 编辑

xvid静态库的封装类(编码和解码)
北京理工大学 20981 陈罡
xvid静态库用起来虽然速度很快,但是很不方便,有必要用c++把它好好封装一下,方便开发人员使用。下面的代码已经在p2p视频会议中采用,很好用,速度也很快。
 
xvid编码器头文件:
#ifndef _XVID_ENCODE_H
#define _XVID_ENCODE_H
#include <xvid.h>
class CXvidEncHandler {
public:
 virtual void PostEncHandler(unsigned char * xvid, int key, int xvid_len) = 0 ;
};
class CXvidEnc {
protected:
 // original encode routine in xvid lib
 int   enc_core(unsigned char *image, unsigned char *bitstream, int *key);
public:
 CXvidEnc() ;
 ~CXvidEnc() ;
 bool            Open();
 bool            Close();
 static void     XVID_GLOBAL_INIT();
 void            Encode(unsigned char * image);
 void   AttachCaller(int width, int height, CXvidEncHandler * enc_caller) ;
protected:
 CXvidEncHandler* m_enc_caller ;
 void *           m_enc_handle;
 unsigned char*   m_bitstream;
 bool             m_closed;
 int        m_key ;
 int     m_width ;
 int     m_height ;
};
#endif
 
编码器源文件:
#include "StdAfx.h"
#include ".\xvidenc.h"
#include "xvid.h"
static const int motion_presets[] = {
 /* quality 0 */
 0,
 /* quality 1 */
 XVID_ME_ADVANCEDDIAMOND16,
 /* quality 2 */
 XVID_ME_ADVANCEDDIAMOND16 | XVID_ME_HALFPELREFINE16,
 /* quality 3 */
 XVID_ME_ADVANCEDDIAMOND16 | XVID_ME_HALFPELREFINE16 |
 XVID_ME_ADVANCEDDIAMOND8 | XVID_ME_HALFPELREFINE8,
 /* quality 4 */
 XVID_ME_ADVANCEDDIAMOND16 | XVID_ME_HALFPELREFINE16 |
 XVID_ME_ADVANCEDDIAMOND8 | XVID_ME_HALFPELREFINE8 |
 XVID_ME_CHROMA_PVOP | XVID_ME_CHROMA_BVOP,
 /* quality 5 */
 XVID_ME_ADVANCEDDIAMOND16 | XVID_ME_HALFPELREFINE16 |
 XVID_ME_ADVANCEDDIAMOND8 | XVID_ME_HALFPELREFINE8 |
 XVID_ME_CHROMA_PVOP | XVID_ME_CHROMA_BVOP,
 /* quality 6 */
 XVID_ME_ADVANCEDDIAMOND16 | XVID_ME_HALFPELREFINE16 | XVID_ME_EXTSEARCH16 |
 XVID_ME_ADVANCEDDIAMOND8 | XVID_ME_HALFPELREFINE8 | XVID_ME_EXTSEARCH8 |
 XVID_ME_CHROMA_PVOP | XVID_ME_CHROMA_BVOP,
};
#define ME_ELEMENTS (sizeof(motion_presets)/sizeof(motion_presets[0]))
static const int vop_presets[] = {
 /* quality 0 */
 0,
 /* quality 1 */
 0,
 /* quality 2 */
 XVID_VOP_HALFPEL,
 /* quality 3 */
 XVID_VOP_HALFPEL | XVID_VOP_INTER4V,
 /* quality 4 */
 XVID_VOP_HALFPEL | XVID_VOP_INTER4V,
 /* quality 5 */
 XVID_VOP_HALFPEL | XVID_VOP_INTER4V |
 XVID_VOP_TRELLISQUANT,
 /* quality 6 */
 XVID_VOP_HALFPEL | XVID_VOP_INTER4V |
 XVID_VOP_TRELLISQUANT | XVID_VOP_HQACPRED,
};
#define VOP_ELEMENTS (sizeof(vop_presets)/sizeof(vop_presets[0]))
//////////////////////////////////////////////////////////////////////////
#define MAX_ZONES   64
/* Maximum number of frames to encode */
#define ABS_MAXFRAMENR 9999
static int ARG_STATS = 0;
static int ARG_DUMP = 0;
static int ARG_LUMIMASKING = 0;
static int ARG_BITRATE = 0;
static int ARG_SINGLE = 0;
static char *ARG_PASS1 = 0;
static char *ARG_PASS2 = 0;
static int ARG_QUALITY = ME_ELEMENTS - 1;
static float ARG_FRAMERATE = 25.00f;
static int ARG_MAXFRAMENR = ABS_MAXFRAMENR;
static int ARG_MAXKEYINTERVAL = 0;
static char *ARG_INPUTFILE = NULL;
static int ARG_INPUTTYPE = 0;
static int ARG_SAVEMPEGSTREAM = 0;
static int ARG_SAVEINDIVIDUAL = 0;
static char *ARG_OUTPUTFILE = NULL;
static int ARG_BQRATIO = 150;
static int ARG_BQOFFSET = 100;
static int ARG_MAXBFRAMES = 0;
static int ARG_PACKED = 0;
static int ARG_VOPDEBUG = 0;
static int ARG_GMC = 0;
static int ARG_INTERLACING = 0;
static int ARG_QPEL = 0;
static int ARG_CLOSED_GOP = 0;
#ifndef READ_PNM
#define IMAGE_SIZE(x,y) ((x)*(y)*3/2)
#else
#define IMAGE_SIZE(x,y) ((x)*(y)*3)
#endif
#define MAX(A,B) ( ((A)>(B)) ? (A) : (B) )
#define SMALL_EPS (1e-10)
#define SWAP(a) ( (((a)&0x000000ff)<<24) | (((a)&0x0000ff00)<<8) | (((a)&0x00ff0000)>>8)  | (((a)&0xff000000)>>24) )
//////////////////////////////////////////////////////////////////////////
CXvidEnc::CXvidEnc()
{
 m_closed = true ;
 m_enc_caller = NULL ;
 m_enc_handle = NULL ;
 m_key = 0 ;
 m_width = 0 ;
 m_height = 0 ;
 m_bitstream = NULL ;
}
CXvidEnc::~CXvidEnc() {
 if(m_bitstream) free(m_bitstream) ;
 m_bitstream = NULL ;
}
bool CXvidEnc::Close() {
 int xerr = 0 ;
 m_closed = true;
 /* Destroy the encoder instance */
 xerr = xvid_encore(m_enc_handle, XVID_ENC_DESTROY, NULL, NULL);
 return (xerr) ? false : true ;
}
void CXvidEnc::AttachCaller(int width, int height, CXvidEncHandler * enc_caller)
{
 m_width = width ;
 m_height = height ;
 m_enc_caller = enc_caller ;
 if(m_width > 0 && m_height > 0) {
  // max size
  int max = (m_width > m_height) ? m_width : m_height ;
  int xvid_len = (int)(max * max) ;
  m_bitstream = (unsigned char *)malloc(xvid_len) ;
  memset(m_bitstream, 0, xvid_len) ;
  CXvidEnc::XVID_GLOBAL_INIT() ;
 }
}
void CXvidEnc::XVID_GLOBAL_INIT(){
 /*------------------------------------------------------------------------
  * XviD core initialization
  *----------------------------------------------------------------------*/
 xvid_gbl_init_t xvid_gbl_init;
 memset(&xvid_gbl_init, 0, sizeof(xvid_gbl_init));
 xvid_gbl_init.version = XVID_VERSION;
 xvid_gbl_init.cpu_flags = XVID_CPU_FORCE | XVID_CPU_ASM ; // here we use asm optimized code
 /* Initialize XviD core -- Should be done once per __process__ */
 xvid_global(NULL, XVID_GBL_INIT, &xvid_gbl_init, NULL);
}
bool CXvidEnc::Open() {
 if(!m_enc_caller) return false ;
 static xvid_enc_create_t xvid_enc_create;
 int xerr = 0;
 m_closed = false;
 /*------------------------------------------------------------------------
 * XviD encoder initialization
 *----------------------------------------------------------------------*/
 memset(&xvid_enc_create, 0, sizeof(xvid_enc_create));
 xvid_enc_create.version = XVID_VERSION;
 /* Width and Height of input frames */
 xvid_enc_create.width = m_width ;
 xvid_enc_create.height = m_height ;
 xvid_enc_create.profile = XVID_PROFILE_AS_L4;
 /* init plugins  */
 /*
 xvid_enc_create.zones = ZONES;
 xvid_enc_create.num_zones = NUM_ZONES;
 xvid_enc_create.plugins = plugins;
 xvid_enc_create.num_plugins = 0;
 */
 /* No fancy thread tests */
 xvid_enc_create.num_threads = 0;
 /* Frame rate - Do some quick float fps = fincr/fbase hack */   
 xvid_enc_create.fincr = 1;
 xvid_enc_create.fbase = (int)10;
 /* Maximum key frame interval */
 xvid_enc_create.max_key_interval = (int)-1;    //--default 10s
 
 /* Bframes settings */
 xvid_enc_create.max_bframes = ARG_MAXBFRAMES;
 xvid_enc_create.bquant_ratio = ARG_BQRATIO;
 xvid_enc_create.bquant_offset = ARG_BQOFFSET;
 
 /* Dropping ratio frame -- we don't need that */
 xvid_enc_create.frame_drop_ratio = 0;
 
 /* Global encoder options */
 xvid_enc_create.global = 0;
 if (ARG_PACKED)
  xvid_enc_create.global |= XVID_GLOBAL_PACKED;
 if (ARG_CLOSED_GOP)
  xvid_enc_create.global |= XVID_GLOBAL_CLOSED_GOP;
 if (ARG_STATS)
  xvid_enc_create.global |= XVID_GLOBAL_EXTRASTATS_ENABLE;
 /* I use a small value here, since will not encode whole movies, but short clips */
 xerr = xvid_encore(NULL, XVID_ENC_CREATE, &xvid_enc_create, NULL);
 
 m_enc_handle = xvid_enc_create.handle;
 
 return true;
}
void CXvidEnc::Encode(unsigned char * image) {
 int ret = 0 ;   
 if(m_closed) return;
 ret = enc_core(image, m_bitstream, &m_key) ;
 // really encode some images into xvid data
 if (ret > 0)
  m_enc_caller->PostEncHandler(m_bitstream, m_key, ret) ;
 }
/*
 raw CXvidEnc procedure
*/
int CXvidEnc::enc_core(unsigned char *image,unsigned char *bitstream, int * key)
{
 int ret;   
 xvid_enc_frame_t xvid_enc_frame;
 xvid_enc_stats_t xvid_enc_stats;
    
 /* Version for the frame and the stats */
 memset(&xvid_enc_frame, 0, sizeof(xvid_enc_frame));
 xvid_enc_frame.version = XVID_VERSION;
 memset(&xvid_enc_stats, 0, sizeof(xvid_enc_stats));
 xvid_enc_stats.version = XVID_VERSION;
 /* Bind output buffer */
 xvid_enc_frame.bitstream = bitstream;
 xvid_enc_frame.length = -1;
    
 /* Initialize input image fields */
 xvid_enc_frame.input.plane[0] = image;
 xvid_enc_frame.input.csp = XVID_CSP_BGR; // suppose we get data from usb web cam
 xvid_enc_frame.input.stride[0] = m_width*3;
 /* Set up core's general features */
 xvid_enc_frame.vol_flags = 0;
     
 /* Set up core's general features */
 xvid_enc_frame.vop_flags = vop_presets[ARG_QUALITY-2];
   
 /* Frame type -- let core decide for us */
 xvid_enc_frame.type = XVID_TYPE_AUTO;
    
 /* Force the right quantizer -- It is internally managed by RC plugins */
 xvid_enc_frame.quant = 0;
 /* Set up motion estimation flags */
 xvid_enc_frame.motion = motion_presets[ARG_QUALITY-2];
 /* We don't use special matrices */
 xvid_enc_frame.quant_intra_matrix = NULL;
 xvid_enc_frame.quant_inter_matrix = NULL;
 /* Encode the frame */
 ret = xvid_encore(m_enc_handle, XVID_ENC_ENCODE, &xvid_enc_frame,NULL);
 //    &xvid_enc_stats);
 //--判别是否是关键帧
 *key = (xvid_enc_frame.out_flags & XVID_KEYFRAME);
 //*stats_type = xvid_enc_stats.type;
 //*stats_quant = xvid_enc_stats.quant;
 //*stats_length = xvid_enc_stats.length;
 //sse[0] = xvid_enc_stats.sse_y;
 //sse[1] = xvid_enc_stats.sse_u;
 //sse[2] = xvid_enc_stats.sse_v;
    
 return (ret);
}
 
解码器头文件:
#ifndef _XVID_DECODE_H
#define _XVID_DECODE_H
 
#include <xvid.h>
 
class CXvidDecHandler {
public:
 virtual void PostDecHandler(unsigned char * image, int used_bytes) = 0 ;
};
class CXvidDec {
public:
 CXvidDec() ;
 ~CXvidDec() ;
 bool               Open();
 bool               Close();
 void               Decode(unsigned char* xvid, int xvid_len);
 static void     XVID_GLOBAL_INIT();
 void      AttachCaller(int width, int height, CXvidDecHandler * dec_caller) ;
protected:
 int                dec_core(unsigned char *bitstream, unsigned char *image, int bs_size) ;
protected:
 CXvidDecHandler*  m_dec_caller ;
 void*             m_dec_handle ;
 unsigned char *   m_image ;
 int      m_width ;
 int      m_height ;
};
#endif
 
解码器源文件:
#include "StdAfx.h"
#include ".\xviddec.h"
#include "xvid.h"
CXvidDec::CXvidDec() {
 m_width = 0 ;
 m_height = 0 ;
 m_image = NULL ;
 m_dec_handle = NULL ;
 m_dec_caller = NULL ;
}
CXvidDec::~CXvidDec()
{
 if(m_image) free(m_image) ;
 m_image = NULL ;
}
void CXvidDec::AttachCaller(int width, int height, CXvidDecHandler * dec_caller)
{
 m_width = width ;
 m_height = height ;
 m_dec_caller = dec_caller ;
 if((m_width > 0) && (m_height > 0)) {
  int image_len = m_width * m_height * 3 ;
  m_image = (unsigned char *)malloc(image_len) ;
  memset(m_image, 0, image_len) ;
  CXvidDec::XVID_GLOBAL_INIT() ;
 }
}
bool CXvidDec::Close(){
 int xerr = 0 ;
 /* Destroy the encoder instance */
 xerr = xvid_decore(m_dec_handle, XVID_ENC_DESTROY, NULL, NULL);
 return (xerr) ? false : true ;
}
void CXvidDec::XVID_GLOBAL_INIT() {
 /*------------------------------------------------------------------------
  * XviD core initialization
  *----------------------------------------------------------------------*/
 xvid_gbl_init_t xvid_gbl_init;
 memset(&xvid_gbl_init, 0, sizeof(xvid_gbl_init));
 xvid_gbl_init.version = XVID_VERSION;
 xvid_gbl_init.cpu_flags = XVID_CPU_FORCE | XVID_CPU_ASM ; // force to use asm optimized routine
 /* Initialize XviD core -- Should be done once per __process__ */
 xvid_global(NULL, XVID_GBL_INIT, &xvid_gbl_init, NULL);
}
bool CXvidDec::Open() {
 if(!m_dec_caller) return false ;
 static xvid_dec_create_t xvid_dec_create ;
 int ret = 0;
 /*------------------------------------------------------------------------
  * XviD encoder initialization
  *----------------------------------------------------------------------*/
 
 memset(&xvid_dec_create, 0, sizeof(xvid_dec_create_t));
 xvid_dec_create.version = XVID_VERSION;
 /* Width and Height of input frames */
 xvid_dec_create.width = m_width ;
 xvid_dec_create.height = m_height ;
 ret = xvid_decore(NULL, XVID_DEC_CREATE, &xvid_dec_create, NULL) ;
 m_dec_handle = xvid_dec_create.handle;
 return true;
}
void CXvidDec::Decode(unsigned char * xvid, int xvid_len) {
 int ret = 0;
 ret = dec_core(xvid, m_image, xvid_len);
 if (ret > 0)
  m_dec_caller->PostDecHandler(m_image, ret) ;  
 }
 /* raw xvid_encode procedure  */
int CXvidDec::dec_core(unsigned char *bitstream,unsigned char *image, int bs_size)
{
 int ret;
 xvid_dec_frame_t xvid_dec_frame;
 /* Reset all structures */
 memset(&xvid_dec_frame, 0, sizeof(xvid_dec_frame_t));
 
 /* Set version */
 xvid_dec_frame.version = XVID_VERSION;
 //xvid_dec_stats->version = XVID_VERSION;
 
 /* No general flags to set */
 xvid_dec_frame.general          = 0;
 
 /* Input stream */
 xvid_dec_frame.bitstream        = bitstream;
 xvid_dec_frame.length           = bs_size;
 
 /* Output frame structure */
 xvid_dec_frame.output.plane[0]  = image;
 xvid_dec_frame.output.stride[0] = m_width*3;
 xvid_dec_frame.output.csp = XVID_CSP_BGR;
 ret = xvid_decore(m_dec_handle, XVID_DEC_DECODE, &xvid_dec_frame, NULL);
 return(ret);   
}
 
大家关注到这里编解码器有两个虚基类:CXvidDecHandler和CXvidEncHandler,使用的时候从这两个类派生,然后重载 它即可。注意,这里是为了配合摄像头使用所以是直接对BGR24格式的数据进行编解码,如果对yuv420原始数据进行编解码,需要略微调整一下代码。
 
在这里我列一下使用流程:
(1)重载虚基类:
class CCapSvrDlg : public CDialog, 
       public CXvidEncHandler,  // xvid encode handler
       public CXvidDecHandler   // xvid decode handler
{ ...
 
(2)重载纯虚函数:
public: // override the CXvidEncHandler
 void PostEncHandler(unsigned char * xvid, int key, int xvid_len) ;
public:
 void PostDecHandler(unsigned char * image, int used_bytes) ;
这里的PostEncHandler和PostDecHandler分别代表编码或者解码完毕后的数据处理。
比如:调用编码,xvid编码完毕后,会自动调用这里重载的PostEncHandler,这里的xvid就是编码后的视频数据,xvid_len就是视频数据的长度,这个key就是标明当前编码是否为关键帧。
解码也是一样,不在赘述。
 
(3)定义编解码器指针:
CXvidEnc *  m_vdo_enc ;
CXvidDec *  m_vdo_dec ;
 
(4)在OnInitDialog中初始化:
 m_vdo_enc = new CXvidEnc() ;
 m_vdo_enc->AttachCaller(320, 240, this) ;
 m_vdo_enc->Open() ;
 
 m_vdo_dec = new CXvidDec() ;
 m_vdo_dec->AttachCaller(320, 240, this) ;
 m_vdo_dec->Open() ;
 
(5)编解码操作:
编码:
m_vdo_enc->Encode(pBuffer) ; // 这里pBuffer是BGR24的320x240的数据
编码如果成功,就会自动调用PostEncHandler函数,就可以得到编码后的结果
 
解码:
m_vdo_dec->Decode(xvid, xvid_len) ; // 传入的存有xvid数据的buffer和长度
解码成功后,会自动调用PostDecHandler,注意对于流媒体数据而言,在这个函数中还有一个形参是标明本次解码用掉了多少个字节的xvid缓冲区的数据,便于下一帧解码的时候调整缓冲区指针
 
(6)OnDestroy函数中,关闭编解码器
 m_vdo_enc->Close() ;
 m_vdo_dec->Close() ;
 delete m_vdo_dec ;
 delete m_vdo_enc ;
 
这些就是全部的xvid静态库的c++封装了,是不是特简单?只要编译一下xvid-core1.1.2即可。
链接的时候,需要libxvidcore.lib。
注意,debug版的需要debug版的libxvidcore.lib,release版的需要release版的xvidcore库。
 

发表于: 2007-06-28,修改于: 2007-06-28 11:09,已浏览3495次

clq
2010-8-19 9:31:32 发表 编辑

以下方法,略有出入. 我上面的方法是验证过的.

//编码结果
class xvid: public CXvidEncHandler
{
public:
    void PostEncHandler(unsigned char * xvid, int key, int xvid_len)
    {
        FILE * f = fopen("c:\\1.raw", "a+b");
        if (f)
        {
            fwrite(xvid, 1, xvid_len, f);
            fclose(f);
        }
   
    }
};

这个 raw 文件改为 avi 就可以用万能播放器播放了,不过不能快进,因为只是原始文件,如果要播放还要再加 avi 头部(怎么加俺还不会 ~O~ )
--------------------------------------------------

CSDN-CSDN社区-C/C++-工具平台和程序库
 有谁用过DLL2Lib??[问题点数:50分]


   
楼主发表于:2006-11-16 23:15:57
我用DLL2Lib1.4把一个DLL转成了一个Lib,在VC2005或者VC6中使用这个生成的Lib的时候,link时提示
“pmjp1.lib(pmjp.obj)   :   warning   LNK4078:   multiple   '.idata '   sections   found   with   different   attributes   (C0100060)”

运行这个程序则崩溃,有人碰到过这种情况吗?如何解决??

   
#1楼 得分:0回复于:2006-11-17 08:56:10
为无LIB的DLL制作LIB函数符号输入库
作者:force_eagle

本文介绍了在VC中针对无LIB时的DLL隐式链接,制作可供VC++使用的LIB函数符号输入库。具体步骤如下:

一、使用VC++的工具DUMPBIN将DLL中的导出函数表导出到一定义(.DEF)文件
EXAMPLE:

DUMPBIN   VideoDeCoder.dll   /EXPROTS   /OUT:VideoDeCoder.def

二、将导出的.DEF文件整理为一符合.DEF个数的函数导出文件
EXAMPLE:VideoDeCoder.DEF   文件内容如下

Dump   of   file   VideoDeCoder.dll                                                                   
                                                                                                                                            
                File   Type:   DLL                                                                                                 
                                                                                                                                            
                    Section   contains   the   following   exports   for   VideoDeCoder.dll   
                                                                                                                                            
                                      0   characteristics                                                                     
                        3D49E48F   time   date   stamp   Fri   Aug   02   09:46:55   2002                   
                                0.00   version                                                                                     
                                      1   ordinal   base                                                                           
                                    11   number   of   functions                                                             
                                    11   number   of   names                                                                     
                                                                                                                                            
                        ordinal   hint   RVA             name                                                                 
                                                                                                                                            
                                    1         0   00010F60   _TM_ClearDecoderBuff@4                             
                                    2         1   00010E80   _TM_CloseDecoder@4                                     
                                    3         2   00010F00   _TM_DecodePicture@4                                   
                                    4         3   00010ED0   _TM_DecodePictureHeader@4                       
                                    5         4   00010FD0   _TM_GetFileEnd@4                                         
                                    6         5   00011030   _TM_GetUValue@4                                           
                                    7         6   00011060   _TM_GetVValue@4                                           
                                    8         7   00011000   _TM_GetYValue@4                                           
                                    9         8   00010E10   _TM_OpenDecoder@8                                       
                                  10         9   00010F30   _TM_ReturnType@4                                         
                                  11         A   00010F90   _TM_SetFileEnd@8                                         
                                                                                                                                            
                    Summary                                                                                                           
                                                                                                                                            
                                2000   .data                                                                                         
                                1000   .rdata                                                                                       
                                1000   .reloc                                                                                       
                              15000   .text 

按照以下方法整理:
1)添加LIB说明

LIBRARY   "VideoDeCoder "                         ; "xx "为DLL名称
DESCRIPTION   "VideoDeCoder   library "   

2)去掉导出函数说明端以外的内容,在LIB说明下添加   "EXPROTS "   说明导出函数

LIBRARY   "VideoDeCoder "
DESCRIPTION   "VideoDeCoder   library "

EXPORTS
                        ordinal   hint   RVA             name                                                   
                                                                                                                              
                                    1         0   00010F60   _TM_ClearDecoderBuff@4                       
                                    2         1   00010E80   _TM_CloseDecoder@4                       
                                    3         2   00010F00   _TM_DecodePicture@                       
                                    4         3   00010ED0   _TM_DecodePictureH                       
                                    5         4   00010FD0   _TM_GetFileEnd@4                           
                                    6         5   00011030   _TM_GetUValue@4                             
                                    7         6   00011060   _TM_GetVValue@4                             
                                    8         7   00011000   _TM_GetYValue@4                             
                                    9         8   00010E10   _TM_OpenDecoder@8                         
                                  10         9   00010F30   _TM_ReturnType@4                           
                                  11         A   00010F90   _TM_SetFileEnd@8 

3)将所有的函数放至行首,去掉   "hint "   和   "RVA "   数据,留下函数的序号   "ordinal "   ,在序号前加上   "@ "   符号   形成   "_导出函数名@参数字节和   @序号 "   此种格式(__stdcall   方式调用导出的函数符号是   "函数名称@参数字节和 ").   最后形成.DEF文件如下:

LIBRARY   "VideoDeCoder "
    DESCRIPTION   "VideoDeCoder   library "

    EXPORTS
          
    TM_ClearDecoderBuff@4                           @1       
    TM_CloseDecoder@4                                   @2       
    TM_DecodePicture@4                                 @3       
    TM_DecodePictureHeader@4                     @4       
    TM_GetFileEnd@4                                       @5       
    TM_GetUValue@4                                         @6       
    TM_GetVValue@4                                         @7       
    TM_GetYValue@4                                         @8       
    TM_OpenDecoder@8                                     @9       
    TM_ReturnType@4                                     @10       
    TM_SetFileEnd@8                                     @11 

三、使用VC++的LIB工具,带/DEF:(.def文件名)   /MACHINE:IX86(80X86机器),就输出符合VC++格式的的LIB文件了.
EXAMPLE:

LIB   /DEF:VideoDeCoder.def   /MACHINE:IX86

四、接时带上LIB文件链接;注意的是当有些动态库DUMPBIN的只有函数名,无 "@nn "的参数格式,如C++Builder写的DLL,输出就只有函数名符号,链接时就会报错:   error   LNK2002:unresolved   external   symbol   "functionname@nn "   提示程序中引入的函数符号无法识别,这时只要将DEF文件中相应的函数名称改为functionname@nn方式,重新建立   LIB,重新链接即可.

 
   
#2楼 得分:0回复于:2006-11-17 08:56:45
dll2lib没用过

#3楼 得分:0回复于:2006-11-17 09:06:50
为什么不用vc++自带的lib工具?

   
#4楼 得分:0回复于:2006-11-17 09:18:28
楼主你字节写不得了   ~~

建立一个   lib   工程,
在这个lib   工程中调用你的   dll,
编译得到   lib。

然后在你需要的地方使用你的   lib   就是了   ...

#5楼 得分:0回复于:2006-11-17 09:23:59
对于楼主你的问题,
看看   DLL2Lib     它的使用要点之类的说明吧   ...

   
#6楼 得分:0回复于:2006-11-17 14:17:43
这个软件的帮助就几页,主要介绍怎么用的,没有说怎么解决出现的问题,网站上也没有其他的信息,发邮件给他们的技术支持也不回,我只能在这里问了。。。。

   
#7楼 得分:0回复于:2006-11-17 14:20:19
“建立一个   lib   工程,
在这个lib   工程中调用你的   dll,
编译得到   lib。

然后在你需要的地方使用你的   lib   就是了   ...”

这样做不就还是要用到原来的DLL吗??我现在的目的是在我的程序里面调用DLL里的函数,但是分发程序的时候又不能出现这个DLL,按照您的说法可以做到吗?

#8楼 得分:0回复于:2006-11-17 14:49:17
dll2lib只能做出符号表吧,不能得到静态的Lib文件。

   
#9楼 得分:0回复于:2006-11-17 14:50:58
我用过,不过没遇到你说的问题,我用vc6,dll2lib有自带的例子,你试一下有无问题
如果也有问题,估计与你的系统或dll2lib版本有关,如果没问题,估计与你的dll有关,你先用一般的方法(LoadLibrary)调用你的dll试试

   
#10楼 得分:0回复于:2006-11-17 14:52:37
to:楼上其他几位,dll2lib是可以将dll转成静态lib的工具(不仅仅是符号表),到目前,我还没找到它的替代工具



   
#11楼 得分:0回复于:2006-11-17 16:07:21
自己写了一个DLL,实现add(),转成Lib可以用;
我需要转的那个DLL,采用Load-Get-Free也可以用,结果正确;
但是转成了Lib就不能用了,remove   idata我也已经勾上去了。。。

   
#12楼 得分:0回复于:2006-11-18 18:23:15
会不会你的dll被压缩或加密过(如用PECompact等工具),这样的话就不行了

 

clq
2010-8-19 9:32:46 发表 编辑

原理可以在网上找一个叫 "XviD 应用编程接口(API)简介(v0.1).pdf" 的文档,写得非常好.

clq
2010-8-19 9:44:03 发表 编辑

http://blog.csdn.net/sunshine1314/archive/2007/10/14/1824432.aspx

avi 格式规范.

clq
2010-8-19 9:56:21 发表 编辑

AVI文件规范

PeterLee 2007-10-14

 

一、AVI文件简介

AVI的英文全称为Audio Video Interleaved,即音频视频交错格式,是将语音和影像同步组合在一起的文件格式。AVI1992年被Microsoft公司推出,随Windows3.1一起被人们所认识和熟知。AVI文件格式多用于音视频捕捉、编辑、回放等应用程序中。通常情况下,一个AVI文件可以包含多个不同类型的媒体流(典型的情况下有一个音频流和一个视频流),不过含有单一音频流或单一视频流的AVI文件也是合法的。AVI可以算是Windows操作系统上最基本的、也是最常用的一种媒体文件格式。

Note: 本文介绍的是基本的AVI文件格式规范,至于newAVI等一些AVI扩展格式,请关注笔者后续文章。

 

二、RIFF文件规范

AVI文件属于一种RIFFResource Interchange File Format的缩写)文件格式,与此同类的还有常见的WAV文件。RIFFMicrosoft提出的一种多媒体文件的存储方式,不同编码的音频、视频文件,可以按照它定义的存储规则保存、记录各自不同的数据。如果读者不熟悉RIFF文件规范,阅读下面章节前,建议先阅读《RIFF文件规范》这篇文章:http://blog.csdn.net/sunshine1314/archive/2007/10/10/1817991.aspx

 

三、AVI文件结构实例分析

1AVI文件结构示例

       1所示为windows系统目录下的clock.avi的文件结构图,其结构是用RIFFspot程序解析得到的,关于RIFFspot程序,感兴趣的读者可以到下面的网址中下载:http://blog.csdn.net/sunshine1314/archive/2007/09/22/1795739.aspx

1 clock.avi文件结构

 

2AVI文件全局结构说明

       如图1所示,整个AVI文件的结构为:一个RIFF + 两个列表(一个用于描述媒体流格式、一个用于保存媒体流数据) + 一个可选的索引块 + 一个JUNK块。

首先,RIFF (AVI ’…)表征了AVI文件类型。然后就是AVI文件必需的第一个列表——‘hdrl’列表,用于描述AVI文件中各个流的格式信息(AVI文件中的每一路媒体数据都称为一个流)。‘hdrl’列表嵌套了一系列块和子列表——首先是一个‘avih’块,用于记录AVI文件的全局信息。然后,就是一个或多个‘strl’子列表。文件中有多少个流,这里就对应有多少个‘strl’子列表,示例clock.avi文件有两路流,既音频流和视频流。

AVI文件中的所有流都使用一个‘strl’子列表说明了以后(注意:‘strl’子列表出现的顺序与媒体流的编号是对应的,比如第一个‘strl’子列表说明的是第一个流(Stream 0),第二个‘strl’子列表说明的是第二个流(Stream 1),以此类推),‘hdrl’列表的任务也就完成了,随后跟着的就是AVI文件必需的第二个列表——‘movi’列表,用于保存真正的媒体流数据(视频图像帧数据或音频采样数据等)。

最后,紧跟在‘hdrl’列表和‘movi’列表之后的,就是AVI文件可选的索引块。这个索引块为AVI文件中每一个媒体数据块进行索引,并且记录它们在文件中的偏移(可能相对于‘movi’列表,也可能相对于AVI文件开头)。

1中还有一种特殊的数据块,用一个四字符码‘JUNK’来表征,它用于内部数据的队齐(填充),应用程序应该忽略这些数据块的实际意义。

 

3’avih’

avih’块,用于记录AVI文件的全局信息,比如流的数量、视频图像的宽和高等,可以使用一个AVIMAINHEADER数据结构来操作: 

typedef struct _avimainheader {
    FOURCC fcc;   //
必须为‘avih
    DWORD  cb;    //
本数据结构的大小,不包括最初的8个字节(fcccb两个域)
    DWORD  dwMicroSecPerFrame;   //
视频帧间隔时间(以毫秒为单位)
    DWORD  dwMaxBytesPerSec;     //
这个AVI文件的最大数据率
    DWORD  dwPaddingGranularity; //
数据填充的粒度
    DWORD  dwFlags;         // AVI
文件的全局标记,比如是否含有索引块等
    DWORD  dwTotalFrames;   //
总帧数
    DWORD  dwInitialFrames; //
为交互格式指定初始帧数(非交互格式应该指定为0
    DWORD  dwStreams;       //
本文件包含的流的个数
    DWORD  dwSuggestedBufferSize; //
建议读取本文件的缓存大小(应能容纳最大的块)
    DWORD  dwWidth;         //
视频图像的宽(以像素为单位)
    DWORD  dwHeight;        //
视频图像的高(以像素为单位)
    DWORD  dwReserved[4];   //
保留
} AVIMAINHEADER;

 

4’strl’子列表

每个‘strl’子列表至少包含一个‘strh’块和一个‘strf’块,而‘strd’块(保存编解码器需要的一些配置信息)和‘strn’块(保存流的名字)是可选的。首先是‘strh’块,用于说明这个流的头信息,可以使用一个AVISTREAMHEADER数据结构来操作: 

typedef struct _avistreamheader {
     FOURCC fcc;  //
必须为‘strh
     DWORD  cb;   //
本数据结构的大小,不包括最初的8个字节(fcccb两个域)
     FOURCC fccType;    //
流的类型:‘auds’(音频流)、‘vids’(视频流)、
                   //
mids’(MIDI流)、‘txts’(文字流)
     FOURCC fccHandler; //
指定流的处理者,对于音视频来说就是解码器
     DWORD  dwFlags;    //
标记:是否允许这个流输出?调色板是否变化?
     WORD   wPriority;  //
流的优先级(当有多个相同类型的流时优先级最高的为默认流)
     WORD   wLanguage;
     DWORD  dwInitialFrames; //
为交互格式指定初始帧数
     DWORD  dwScale;   //
这个流使用的时间尺度
     DWORD  dwRate;
     DWORD  dwStart;   //
流的开始时间
     DWORD  dwLength;  //
流的长度(单位与dwScaledwRate的定义有关)
     DWORD  dwSuggestedBufferSize; //
读取这个流数据建议使用的缓存大小
     DWORD  dwQuality;    //
流数据的质量指标(0 ~ 10,000
     DWORD  dwSampleSize; // Sample
的大小
     struct {
         short int left;
         short int top;
         short int right;
         short int bottom;
}  rcFrame;  //
指定这个流(视频流或文字流)在视频主窗口中的显示位置
             //
视频主窗口由AVIMAINHEADER结构中的dwWidthdwHeight决定
} AVISTREAMHEADER;

 

然后是‘strf’块,用于说明流的具体格式。如果是视频流,则使用一个BITMAPINFO数据结构来描述;如果是音频流,则使用一个WAVEFORMATEX数据结构来描述。

 

5‘movi’列表

‘movi’列表保存的是真正的媒体流数据,其数据组织方式有两种。可以将数据块直接嵌在‘movi’列表里面,也可以将几个数据块分组成一个‘rec ’列表后再编排进‘movi’列表。

AVI文件中包含有多个流的时候,数据块与数据块之间如何来区别呢?数据块使用了一个四字符码来表征它的类型,这个四字符码由2个字节的类型码和2个字节的流编号组成。标准的类型码定义如下:‘db’(非压缩视频帧)、‘dc’(压缩视频帧)、‘pc’(改用新的调色板)、‘wb’(音缩视频)。比如第一个流(Stream 0)是音频,则表征音频数据块的四字符码为‘00wb’;第二个流(Stream 1)是视频,则表征视频数据块的四字符码为‘00db’‘00dc’。对于视频数据来说,在AVI数据序列中间还可以定义一个新的调色板,每个改变的调色板数据块用‘xxpc’来表征,新的调色板使用一个数据结构AVIPALCHANGE来定义。(注意:如果一个流的调色板中途可能改变,则应在这个流格式的描述中,也就是AVISTREAMHEADER结构的dwFlags中包含一个AVISF_VIDEO_PALCHANGES标记)。另外,文字流数据块可以使用随意的类型码表征。

 

6AVI索引块

索引块使用一个四字符码‘idx1’来表征,索引信息使用一个数据结构来AVIOLDINDEX定义。 

typedef struct _avioldindex {
   FOURCC  fcc;  //
必须为‘idx1
   DWORD   cb;   //
本数据结构的大小,不包括最初的8个字节(fcccb两个域)
   struct _avioldindex_entry {
      DWORD   dwChunkId;   //
表征本数据块的四字符码
      DWORD   dwFlags;     //
说明本数据块是不是关键帧、是不是‘rec ’列表等信息
      DWORD   dwOffset;    //
本数据块在文件中的偏移量
      DWORD   dwSize;      //
本数据块的大小
  } aIndex[]; //
这是一个数组!为每个媒体数据块都定义一个索引信息
} AVIOLDINDEX;

 注意:如果一个AVI文件包含有索引块,则应在主AVI信息头的描述中,也就是AVIMAINHEADER结构的dwFlags中包含一个AVIF_HASINDEX标记。

 

四、后记

       大家应该都听过“AVI文件不适合用于流媒体传输”这样的说法,通过本文对AVI文件结构的解析,相信大家对这种说法有更清晰的验证,因为AVI文件结构中置于文件尾部的索引块、头部信息中规定的文件长度等过多的选项都是不适合流媒体应用的。

 

Note: 本文内容节选自 AVI文件格式----摘自《DirectShow实务精选》 作者:陆其明, 并作了整理。

clq
2010-8-19 11:26:03 发表 编辑

http://read.pudn.com/downloads37/sourcecode/multimedia/audio/123799/libac3dec/test/testac3dec.c__.htm
一个写入音频的例子
--------------------------------------------------
  1. /*  
  2. * This source code is free software; you can redistribute it and/or  
  3. * modify it under the terms of the GNU Lesser General Public  
  4. * License as published by the Free Software Foundation; either  
  5. * version 2 of the License, or (at your option) any later version.  
  6.  
  7. * This library is distributed in the hope that it will be useful,  
  8. * but WITHOUT ANY WARRANTY; without even the implied warranty of  
  9. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU  
  10. * Lesser General Public License for more details.  
  11. *         
  12. * You should have received a copy of the GNU Lesser General Public  
  13. * License along with this library; if not, write to the Free Software  
  14. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA  
  15.  
  16. * File Name: testac3dec.c                             
  17.  
  18. * Reference:  
  19.  
  20. * Author: Li Feng,  fli_linux@yahoo.com.cn                                                   
  21.  
  22. * Description:  
  23.  
  24. *     
  25. *   
  26. * History:  
  27. * 02/23/2005  Li Feng    Created  
  28. *    
  29.  
  30. *CodeReview Log:  
  31. *   
  32. */   
  33. #include <stdio.h>   
  34. #include <string.h>   
  35. #include "libac3dec.h"   
  36.    
  37. typedef signed char         INT8;   
  38. typedef signed short        INT16;   
  39. typedef signed int          INT32;   
  40. typedef unsigned char       UINT8;   
  41. typedef unsigned short      UINT16;   
  42. typedef unsigned long        UINT32;   
  43.    
  44. #define PCM_FRAME_SIZE 2048*4   
  45.    
  46. #define WAVE_FORMAT_PCM 1   
  47.    
  48. #define SWAP32(val) (UINT32)((((UINT32)(val)) & 0x000000FF)<<24|  \   
  49.     (((UINT32)(val)) & 0x0000FF00)<<8 |   \   
  50.     (((UINT32)(val)) & 0x00FF0000)>>8 |   \   
  51.     (((UINT32)(val)) & 0xFF000000)>>24)      
  52.    
  53.    
  54. #pragma pack(push,1)   
  55.    
  56. typedef struct _riffchunk   
  57. {   
  58.     UINT32 fcc;   
  59.     UINT32  cb;   
  60. } RIFFCHUNK, *LPRIFFCHUNK;   
  61.    
  62. typedef struct _rifflist    
  63. {   
  64.     UINT32 fcc;   
  65.     UINT32  cb;   
  66.     UINT32 fccListType;   
  67. } RIFFLIST , *LPRIFFLIST;   
  68.    
  69. #define RIFFROUND(cb) ((cb) + ((cb)&1))   
  70.    
  71. #define RIFFNEXT(pChunk) (LPRIFFCHUNK)((LPBYTE)(pChunk) \   
  72.     + sizeof(RIFFCHUNK) \   
  73. + RIFFROUND(((LPRIFFCHUNK)pChunk)->cb))   
  74. typedef struct    
  75. {   
  76.     UINT32 fcc;   
  77.     UINT32 cb;   
  78.     UINT16  wFormatTag;    
  79.     UINT16  nChannels;    
  80.     UINT32 nSamplesPerSec;    
  81.     UINT32 nAvgBytesPerSec;    
  82.     UINT16  nBlockAlign;    
  83.     UINT16  wBitsPerSample;    
  84. }WAVEFORM;   
  85.    
  86. #pragma pack(pop)   
  87.    
  88. const UINT32 WAVE_HEAD_LEN=44;   
  89. static UINT8 head[44];     
  90.    
  91. void SetWaveHead(UINT32 dwDataLen, UINT32 nSampleRate, UINT32 nChannel)   
  92. {   
  93.     RIFFCHUNK *pch;   
  94.     RIFFLIST  *priff;   
  95.     WAVEFORM *pwave;   
  96.        
  97.     memset(&head,0x00,WAVE_HEAD_LEN);   
  98.     priff=(RIFFLIST*)head;   
  99.     priff->fcc=0x46464952;//SWAP32('RIFF');   
  100.     if(dwDataLen)   
  101.         priff->cb=dwDataLen+WAVE_HEAD_LEN-sizeof(RIFFCHUNK);   
  102.     priff->fccListType=0x45564157;//SWAP32('WAVE');   
  103.     pwave=(WAVEFORM*)(priff+1);   
  104.     pwave->fcc=0x20746d66;//SWAP32('fmt ');   
  105.     pwave->cb=sizeof(WAVEFORM)-sizeof(RIFFCHUNK);   
  106.     pwave->wFormatTag=WAVE_FORMAT_PCM;   
  107.     pwave->nChannels=nChannel;   
  108.     pwave->nSamplesPerSec=nSampleRate;   
  109.     pwave->nAvgBytesPerSec=pwave->nSamplesPerSec*nChannel*2;   
  110.     pwave->nBlockAlign=nChannel*2;   
  111.     pwave->wBitsPerSample=16;   
  112.     pch=(RIFFCHUNK*)(pwave+1);   
  113.     pch->fcc=0x61746164;//SWAP32('data');   
  114.     if(dwDataLen)   
  115.     {   
  116.         pch->cb = dwDataLen;   
  117.     }   
  118. }   
  119.    
  120. #define BUF_SIZE 1024   
  121.    
  122. int SearchSyncWord(FILE *fp)   
  123. {   
  124.     unsigned char syncWord[2];   
  125.     int i=0;   
  126.     if(fread(syncWord, 1, 2, fp)!=2)   
  127.         return 0;   
  128.     do    
  129.     {   
  130.         if(syncWord[0] == 0x0B && syncWord[1] == 0x77)   
  131.         {   
  132.             return 1;   
  133.         }   
  134.         i++;   
  135.         syncWord[0] = syncWord[1];   
  136.     }    
  137.     while(fread(syncWord+1,1,1, fp));   
  138.     return 1;   
  139. }   
  140.    
  141. int main(int argc, char **argv)   
  142. {   
  143.     FILE *fpInput;   
  144.     FILE *fpOutput;   
  145.     signed short data[PCM_FRAME_SIZE];   
  146.     unsigned char mpa_data[1792];   
  147.     int nRead = 0;   
  148.     UINT32 nDataLen;   
  149.     UINT32 nFileLen = 0;   
  150.     UINT32 nFrameSize;   
  151.     UINT32 nFrameLen;   
  152.     UINT32 nSampleRate;   
  153.     UINT32 n = 0;   
  154.        
  155.     if(argc<3)   
  156.         return 0;   
  157.        
  158.     fpInput = fopen(argv[1], "rb");   
  159.     fpOutput= fopen(argv[2], "wb");   
  160.     if(fpInput==NULL ||fpOutput==NULL)   
  161.     {   
  162.         printf("open file error\n");   
  163.         goto err;   
  164.     }   
  165.        
  166.     fwrite(head, 1, WAVE_HEAD_LEN, fpOutput);   
  167.     if(fread(mpa_data, 1, 5, fpInput)!=5)   
  168.     {   
  169.         goto err;   
  170.     }   
  171.     if(AC3_GetAudioInfo(&nFrameSize, &nSampleRate, mpa_data)==0)   
  172.     {   
  173.         printf("AC3_GetAudioInfo Error1\n");   
  174.         goto err;   
  175.     }   
  176.     printf("nFrameSize=%d, nSampleRate = %d \n",nFrameSize,nSampleRate );   
  177.    
  178.     while((fread(mpa_data+5, 1, nFrameSize-5, fpInput))==nFrameSize-5)   
  179.     {   
  180.         nFrameLen = AC3_SampleConvert(data, &nDataLen, mpa_data, nFrameSize);   
  181.         if(nDataLen>0)   
  182.         {   
  183.             fwrite(data, 1, nDataLen, fpOutput);   
  184.             nFileLen += nDataLen;   
  185.         }   
  186.         if(SearchSyncWord(fpInput)==0)   
  187.             break;   
  188.         memset(mpa_data, 0, 1792);   
  189.         mpa_data[0] = 0x0B;   
  190.         mpa_data[1] = 0x77;   
  191.         if(fread(mpa_data+2, 1, 3, fpInput)!=3)   
  192.         {   
  193.             goto err;   
  194.         }   
  195.            
  196.         if(AC3_GetAudioInfo(&nFrameSize, &nSampleRate, mpa_data)==0)   
  197.         {   
  198.             printf("AC3_GetAudioInfo Error\n");   
  199.             break;   
  200.         }   
  201.         printf("nFrameSize=%d, nSampleRate = %d \n",nFrameSize,nSampleRate );   
  202.            
  203.         n++;   
  204.         printf("decode %d frame\n", n);   
  205.     }   
  206.     printf("nSampleRate = %d\n", nSampleRate);   
  207.     SetWaveHead(nFileLen, nSampleRate, 2);   
  208.     fseek(fpOutput, 0, SEEK_SET);   
  209.     fwrite(head, 1, WAVE_HEAD_LEN, fpOutput);   
  210.        
  211. err:   
  212.     if(fpInput)   
  213.     {   
  214.         fclose(fpInput);   
  215.     }   
  216.     if(fpOutput)   
  217.     {   
  218.         fclose(fpOutput);   
  219.     }   
  220.     return 0;   
  221. }   
  222.    
  223.    
  224. </string.h></stdio.h>


clq
2010-8-19 11:28:31 发表 编辑

其实他那个解析结构有误导嫌疑,实际上没有把 avi 文件外层的 riff 表示出来.


总数:7 页次:1/1 首页 尾页  
总数:7 页次:1/1 首页 尾页  


所在合集/目录



发表评论:
文本/html模式切换 插入图片 文本/html模式切换


附件:



NEWBT官方QQ群1: 276678893
可求档连环画,漫画;询问文本处理大师等软件使用技巧;求档softhub软件下载及使用技巧.
但不可"开车",严禁国家敏感话题,不可求档涉及版权的文档软件.
验证问题说明申请入群原因即可.

Copyright © 2005-2020 clq, All Rights Reserved
版权所有
桂ICP备15002303号-1