YUV视频格式到RGB32格式转换的速度优化 上篇
                    HouSisong@GMail.com    2007.10.30
 
tag: YUV,YCbCr,YUV到RGB颜色转换,YUV解码,VFW,视频,MMX,SSE,多核优化
  
摘要: 我们得到的很多视频数据(一些解码器的输出或者摄像头的输出等)都使用了一种
叫YUV的颜色格式;本文介绍了常见的YUV视频格式(YUY2/YVYU/UYVY/I420/YV12等)到
RGB颜色格式的转换,并尝试对转化的速度进行优化;
  全文 分为:   
    《上篇》文章首先介绍了YUV颜色格式,并介绍了YUV颜色格式和RGB颜色格式之
间的相互转换;然后重点介绍了YUYV视频格式到RGB32格式的转化,并尝试进行了一
些速度优化;
    《中篇》尝试使用MMX/SSE指令对前面实现的解码器核心进行速度优化;然
后简要介绍了一个使用这类CPU特殊指令时的代码框架,使得解码程序能够根据运行时
的CPU指令支持情况动态调用最佳的实现代码;并最终提供一个多核并行的优化版本;
    《下篇》介绍YUV类型的其他种类繁多的视频数据编码格式;并将前面实现的解码
器核心(在不损失代码速度的前提下)进行必要的修改,使之适用于这些YUV视频格式
的解码;
  (2010.11.23  color_table查询表扩大范围,以避免 color_table[Ye  +  csU_blue_16  *  Ue ) >> 16 )]超界; 谢谢bug提交者 少浦 .)
  (2007.11.13  修正了一下颜色转换公式中的系数)       
  (2007.11.04  增加一个更深优化的全查表的实现DECODE_YUYV_TableEx;      
        对DECODE_YUYV_Common做了一点小的调整和改进)
       
正文:
  代码使用C++,编译器:VC2005
  涉及到汇编的时候假定为x86平台;
  现在的高清视频帧尺寸越来越大,所以本文测试的图片大小将使用1024x576和
1920x1080两种常见的帧尺寸来测试解码器速度;
  测试平台:(CPU:AMD64x2 4200+(2.37G);   内存:DDR2 677(双通道); 编译器:VC2005)
  测试平台:(CPU:Intel Core2 4400(2.00G);内存:DDR2 667(双通道); 编译器:VC2005)
 
 
A:YUV颜色空间介绍,YUV颜色空间和RGB颜色空间的转换公式
   YUV(或称为YCbCr)颜色空间中Y代表亮度,“U”和“V”表示的则是色度。
   (这里假设YUV和RGB的颜色分量值都是无符号的8bit整数)

RGB颜色空间到YUV颜色空间的转换公式:
  
    Y= 0.256788*R + 0.504129*G + 0.097906*B +  16;
    U=-0.148223*R - 0.290993*G + 0.439216*B + 128;
    V= 0.439216*R - 0.367788*G - 0.071427*B + 128;

YUV颜色空间到RGB颜色空间的转换公式:
    B= 1.164383 * (Y - 16) + 2.017232*(U - 128);
    G= 1.164383 * (Y - 16) - 0.391762*(U - 128) - 0.812968*(V - 128);
    R= 1.164383 * (Y - 16) + 1.596027*(V - 128);

( 补充:
      在视频格式中基本上都用的上面的转换公式;但在其他一些
地方可能会使用下面的转换公式(不同的使用场合可能有不同的转换系数):

Y =  0.299*R + 0.587*G + 0.114*B;
    U = -0.147*R - 0.289*G + 0.436*B;
    V =  0.615*R - 0.515*G - 0.100*B;

R = Y + 1.14*V;
    G = Y - 0.39*U - 0.58*V;
    B = Y + 2.03*U;
  )
 
B.RGB32颜色和图片的数据定义:

#define  asm __asm

typedef unsigned  char  TUInt8;  //  [0..255]
typedef unsigned long  TUInt32;
struct  TARGB32       // 32 bit color
{
    TUInt8  b,g,r,a;           // a is alpha
};

struct  TPicRegion   // 一块颜色数据区的描述,便于参数传递
{
    TARGB32 *     pdata;          // 颜色数据首地址
     long         byte_width;     // 一行数据的物理宽度(字节宽度);
                 // abs(byte_width)有可能大于等于width*sizeof(TARGB32);
     long         width;          // 像素宽度
     long         height;         // 像素高度
};

// 那么访问一个点的函数可以写为:
__forceinline TARGB32 &  Pixels( const  TPicRegion &  pic, const   long  x, const   long  y)
{
     return  ( (TARGB32 * )((TUInt8 * )pic.pdata + pic.byte_width * y) )[x];
}

(注意:__forceinline表示总是内联代码,如果你的编译器不支持,请改写为inline关键词)

C.YUYV(也可以叫做YUY2)视频格式到RGB32的转化
(本文先集中优化YUYV视频格式到RGB32的转化,然后再扩展到其他视频格式)

YUYV视频格式的内存数据布局图示:
 
  
  图中可以看出Y的数据量是U或者V的两倍,这是因为人的眼睛一般对亮度比对颜
色更敏感一些,所以将连续的两个像素的U(或V)值只保存一个U(或V)值,那么每个
像素平均占用16bit储存空间; 
  解码YUYV视频格式的一个简单浮点实现:

     // 颜色饱和函数
    __forceinline  long  border_color( long  color)
    {
         if  (color > 255 )
             return   255 ;
         else   if  (color < 0 )
             return   0 ;
         else
             return  color;
    }

__forceinline TARGB32 YUVToRGB32_float( const  TUInt8 Y, const  TUInt8 U, const  TUInt8 V)
    {
        TARGB32 result;
        result.b= border_color( 1.164383 * (Y - 16) + 2.017232*(U - 128) );
        result.g= border_color( 1.164383 * (Y - 16) - 0.391762*(U - 128) - 0.812968*(V - 128) );
        result.r= border_color( 1.164383 * (Y - 16) + 1.596027*(V - 128) );
        result.a =   255 ;
         return  result;
    }

void  DECODE_YUYV_Float( const  TUInt8 *  pYUYV, const  TPicRegion &  DstPic)
{
    assert((DstPic.width  &   1 ) == 0 ); 
    
    TARGB32 *  pDstLine = DstPic.pdata; 
     for  ( long  y = 0 ;y < DstPic.height; ++ y)
    {
         for  ( long  x = 0 ;x < DstPic.width;x += 2 )
        {
            pDstLine[x + 0 ] = YUVToRGB32_float(pYUYV[ 0 ],pYUYV[ 1 ],pYUYV[ 3 ]);
            pDstLine[x + 1 ] = YUVToRGB32_float(pYUYV[ 2 ],pYUYV[ 1 ],pYUYV[ 3 ]);
            pYUYV += 4 ;
        }
        ((TUInt8 *& )pDstLine) += DstPic.byte_width;
    }    
}

速度测试:

//==============================================================================
//                       |        1024x576       |       1920x1080       |
//------------------------------------------------------------------------------
//                       |  AMD64x2  |   Core2   |  AMD64x2  |   Core2   |
//------------------------------------------------------------------------------
//DECODE_YUYV_Float         55.0 FPS   63.7 FPS     15.6 FPS   18.0 FPS

D.使用整数运算(定点数运算)来代替浮点运算
   默认的浮点数到整数的转换是比较慢的运算;这里用整数运算来代替浮点运算;
   使用16位定点数,原理是将浮点系数扩大2^16倍,并保存为整数(引入很小的误差),那么计算出来的值
再除以2^16就得到正确的结果了,而除以2^16可以优化为带符号的右移; 代码如下:

         const   int  csY_coeff_16  =   1.164383*(1<<16);
         const   int  csU_blue_16   =   2.017232*(1<<16);
         const   int  csU_green_16  =  (-0.391762)*(1<<16);  
          const   int  csV_green_16  =  (-0.812968)*(1<<16);
         const   int  csV_red_16    =   1.596027*(1<<16);

__forceinline TARGB32 YUVToRGB32_Int( const  TUInt8 Y, const  TUInt8 U, const  TUInt8 V)
    {
        TARGB32 result;
         int  Ye = csY_coeff_16  *  (Y  -   16 ); 
         int  Ue = U - 128 ;
         int  Ve = V - 128 ;
        result.b =  border_color( ( Ye  +  csU_blue_16  *  Ue ) >> 16  );
        result.g =  border_color( ( Ye  +  csU_green_16  *  Ue  +  csV_green_16  *  Ve ) >> 16  );
        result.r =  border_color( ( Ye  +  csV_red_16  *  Ve ) >> 16  );
        result.a =   255 ;
         return  result;
    }

void  DECODE_YUYV_Int( const  TUInt8 *  pYUYV, const  TPicRegion &  DstPic)
{
    assert((DstPic.width  &   1 ) == 0 ); 
    
    TARGB32 *  pDstLine = DstPic.pdata; 
     for  ( long  y = 0 ;y < DstPic.height; ++ y)
    {
         for  ( long  x = 0 ;x < DstPic.width;x += 2 )
        {
            pDstLine[x + 0 ] = YUVToRGB32_Int(pYUYV[ 0 ],pYUYV[ 1 ],pYUYV[ 3 ]);
            pDstLine[x + 1 ] = YUVToRGB32_Int(pYUYV[ 2 ],pYUYV[ 1 ],pYUYV[ 3 ]);
            pYUYV += 4 ;
        }
        ((TUInt8 *& )pDstLine) += DstPic.byte_width;
    }  
}

速度测试:

//==============================================================================
//                       |        1024x576       |       1920x1080       |
//------------------------------------------------------------------------------
//                       |  AMD64x2  |   Core2   |  AMD64x2  |   Core2   |
//------------------------------------------------------------------------------
//DECODE_YUYV_Int          137.1 FPS  131.9 FPS     39.0 FPS   37.1 FPS

E.优化border_color颜色饱和函数
  因为border_color的实现使用了分支代码,在现代CPU上分支预测错的代价很大,这里使用一个
查找表来代替它;

// 颜色查表
static  TUInt8 _color_table[ 256 * 5 ];
static   const  TUInt8 *  color_table =& _color_table[ 256 *2];
class  _CAuto_inti_color_table
{
public :
    _CAuto_inti_color_table() {
         for  ( int  i = 0 ;i < 256 *5 ; ++ i)
            _color_table[i] = border_color(i - 256*2 );
    }
};
static  _CAuto_inti_color_table _Auto_inti_color_table;

__forceinline TARGB32 YUVToRGB32_RGBTable( const  TUInt8 Y, const  TUInt8 U, const  TUInt8 V)
    {

TARGB32 result;
         int  Ye = csY_coeff_16  *  (Y  -   16 ); 
         int  Ue = U - 128 ;
         int  Ve = V - 128 ;
        result.b =  color_table[ ( Ye  +  csU_blue_16  *  Ue ) >> 16  ];
        result.g =  color_table[ ( Ye  +  csU_green_16  *  Ue  +  csV_green_16  *  Ve ) >> 16  ];
        result.r =  color_table[ ( Ye  +  csV_red_16  *  Ve ) >> 16  ];
        result.a =   255 ;
         return  result;
    }

void  DECODE_YUYV_RGBTable( const  TUInt8 *  pYUYV, const  TPicRegion &  DstPic)
{
    assert((DstPic.width  &   1 ) == 0 ); 
    
    TARGB32 *  pDstLine = DstPic.pdata; 
     for  ( long  y = 0 ;y < DstPic.height; ++ y)
    {
         for  ( long  x = 0 ;x < DstPic.width;x += 2 )
        {
            pDstLine[x + 0 ] = YUVToRGB32_RGBTable(pYUYV[ 0 ],pYUYV[ 1 ],pYUYV[ 3 ]);
            pDstLine[x + 1 ] = YUVToRGB32_RGBTable(pYUYV[ 2 ],pYUYV[ 1 ],pYUYV[ 3 ]);
            pYUYV += 4 ;
        }
        ((TUInt8 *& )pDstLine) += DstPic.byte_width;
    }    
}

速度测试:

//==============================================================================
//                       |        1024x576       |       1920x1080       |
//------------------------------------------------------------------------------
//                       |  AMD64x2  |   Core2   |  AMD64x2  |   Core2   |
//------------------------------------------------------------------------------
//DECODE_YUYV_RGBTable     164.8 FPS  152.9 FPS     47.1 FPS   43.7 FPS

F.使用查找表来代乘法运算
  其实,现在的x86 CPU做乘法是很快的,用查找表的内存访问来代替乘法不见得会更快;
本文章讨论它的意义在于,该实现版本在其他平台的CPU上可能有很好的优化效果;在奔腾4上
该版本DECODE_YUYV_Table也很可能比DECODE_YUYV_RGBTable快,我没有测试过;

static   int  Ym_table[ 256 ];
static   int  Um_blue_table[ 256 ];
static   int  Um_green_table[ 256 ];
static   int  Vm_green_table[ 256 ];
static   int  Vm_red_table[ 256 ];

class  _CAuto_inti_yuv_table
{
public :
    _CAuto_inti_yuv_table() {
         for  ( int  i = 0 ;i < 256 ; ++ i)
        {
            Ym_table[i] = csY_coeff_16  *  (i  -   16 );
            Um_blue_table[i] = csU_blue_16  *  (i  -   128 );
            Um_green_table[i] = csU_green_16  *  (i  -   128 );
            Vm_green_table[i] = csV_green_16  *  (i  -   128 );
            Vm_red_table[i] = csV_red_16  *  (i  -   128 );
        }
    }
};
static  _CAuto_inti_yuv_table _Auto_inti_yuv_table;

__forceinline TARGB32 YUVToRGB32_Table( const  TUInt8 Y, const  TUInt8 U, const  TUInt8 V)
    {
        TARGB32 result;
         int  Ye = Ym_table[Y]; 
        result.b =  color_table[ ( Ye  +  Um_blue_table[U] ) >> 16  ];
        result.g =  color_table[ ( Ye  +  Um_green_table[U]  +  Vm_green_table[V] ) >> 16  ];
        result.r =  color_table[ ( Ye  +  Vm_red_table[V] ) >> 16  ];
        result.a =   255 ;
         return  result;
    }

void  DECODE_YUYV_Table( const  TUInt8 *  pYUYV, const  TPicRegion &  DstPic)
{
    assert((DstPic.width  &   1 ) == 0 ); 
    
    TARGB32 *  pDstLine = DstPic.pdata; 
     for  ( long  y = 0 ;y < DstPic.height; ++ y)
    {
         for  ( long  x = 0 ;x < DstPic.width;x += 2 )
        {
            pDstLine[x + 0 ] = YUVToRGB32_Table(pYUYV[ 0 ],pYUYV[ 1 ],pYUYV[ 3 ]);
            pDstLine[x + 1 ] = YUVToRGB32_Table(pYUYV[ 2 ],pYUYV[ 1 ],pYUYV[ 3 ]);
            pYUYV += 4 ;
        }
        ((TUInt8 *& )pDstLine) += DstPic.byte_width;
    }    
}

速度测试:

//==============================================================================
//                       |        1024x576       |       1920x1080       |
//------------------------------------------------------------------------------
//                       |  AMD64x2  |   Core2   |  AMD64x2  |   Core2   |
//------------------------------------------------------------------------------
//DECODE_YUYV_Table        146.1 FPS  151.3 FPS     41.8 FPS   43.5 FPS

(提示:在没有“带符号右移”的CPU体系下或者能够忍受一点点小的误差,可以在生成YUV的查找表的时候不扩大2^16倍,从而在计算出结果的时候也就不需要右移16位的修正了,这样改进后函数速度还会提高一些)

2007.11.04 补充一个更深优化的全查表的实现DECODE_YUYV_TableEx;

// 全查表
static   int  Ym_tableEx[ 256 ];
static   int  Um_blue_tableEx[ 256 ];
static   int  Um_green_tableEx[ 256 ];
static   int  Vm_green_tableEx[ 256 ];
static   int  Vm_red_tableEx[ 256 ];

class  _CAuto_inti_yuv_tableEx
{
public :
    _CAuto_inti_yuv_tableEx() {
         for  ( int  i = 0 ;i < 256 ; ++ i)
        {
            Ym_tableEx[i] = (csY_coeff_16  *  (i  -   16 ) ) >> 16 ;
            Um_blue_tableEx[i] = (csU_blue_16  *  (i  -   128 ) ) >> 16 ;
            Um_green_tableEx[i] = (csU_green_16  *  (i  -   128 ) ) >> 16 ;
            Vm_green_tableEx[i] = (csV_green_16  *  (i  -   128 ) ) >> 16 ;
            Vm_red_tableEx[i] = (csV_red_16  *  (i  -   128 ) ) >> 16 ;
        }
    }
};
static  _CAuto_inti_yuv_tableEx _Auto_inti_yuv_tableEx;

__forceinline  void  YUVToRGB32_Two_TableEx(TARGB32 *  pDst, const  TUInt8 Y0, const  TUInt8 Y1, const  TUInt8 U, const  TUInt8 V)
    {
         int  Ye0 = Ym_tableEx[Y0]; 
         int  Ye1 = Ym_tableEx[Y1];
         int  Ue_blue = Um_blue_tableEx[U];
         int  Ue_green = Um_green_tableEx[U];
         int  Ve_green = Vm_green_tableEx[V];
         int  Ve_red = Vm_red_tableEx[V];
         int  UeVe_green = Ue_green + Ve_green;

((TUInt32 * )pDst)[ 0 ] = color_table[ ( Ye0  +  Ue_blue ) ] 
                     |  ( color_table[ ( Ye0  +  UeVe_green )] << 8  )
                     |  ( color_table[ ( Ye0  +  Ve_red )] << 16  )
                     |  (  255 << 24 );
        ((TUInt32 * )pDst)[ 1 ] = color_table[ ( Ye1  +  Ue_blue ) ] 
                     |  ( color_table[ ( Ye1  +  UeVe_green )] << 8  )
                     |  ( color_table[ ( Ye1  +  Ve_red )] << 16  )
                     |  (  255 << 24 );
    }

void  DECODE_YUYV_TableEx_line(TARGB32 *  pDstLine, const  TUInt8 *  pYUYV, long  width)
    {
         for  ( long  x = 0 ;x < width;x += 2 )
        {
            YUVToRGB32_Two_TableEx( & pDstLine[x],pYUYV[ 0 ],pYUYV[ 2 ],pYUYV[ 1 ],pYUYV[ 3 ]);
            pYUYV += 4 ;
        }
    }

void  DECODE_YUYV_TableEx( const  TUInt8 *  pYUYV, const  TPicRegion &  DstPic)
{
    assert((DstPic.width  &   1 ) == 0 ); 
    
     long  YUV_byte_width = (DstPic.width >> 1 ) << 2 ;
    TARGB32 *  pDstLine = DstPic.pdata; 
     for  ( long  y = 0 ;y < DstPic.height; ++ y)
    {
        DECODE_YUYV_TableEx_line(pDstLine,pYUYV,DstPic.width);
        pYUYV += YUV_byte_width;
        ((TUInt8 *& )pDstLine) += DstPic.byte_width;
    }    
}

速度测试:

//==============================================================================
//                       |        1024x576       |       1920x1080       |
//------------------------------------------------------------------------------
//                       |  AMD64x2  |   Core2   |  AMD64x2  |   Core2   |
//------------------------------------------------------------------------------
//DECODE_YUYV_TableEx      236.5 FPS  300.5 FPS     68.1 FPS   85.0 FPS

G.优化U和V的计算、合并写内存
  由于两个像素共享U和V值,关于它们的两次计算,有部分代码可以共享;
所以实现一个一次转换两个像素的版本;
  写内存的时候,合并成4字节来写,这样在现在的CPU上更加有效率(注意:在intel的
Xeon CPU上这个改动反而会慢一些):

    __forceinline  void  YUVToRGB32_Two(TARGB32 *  pDst, const  TUInt8 Y0, const  TUInt8 Y1, const  TUInt8 U, const  TUInt8 V)
    {
         int  Ye0 = csY_coeff_16  *  (Y0  -   16 ); 
         int  Ye1 = csY_coeff_16  *  (Y1  -   16 );
         int  Ue = (U - 128 );
         int  Ue_blue = csU_blue_16  * Ue;
         int  Ue_green = csU_green_16  * Ue;
         int  Ve = (V - 128 );
         int  Ve_green = csV_green_16  * Ve;
         int  Ve_red = csV_red_16  * Ve;
         int  UeVe_green = Ue_green + Ve_green;

((TUInt32 * )pDst)[ 0 ] = color_table[ ( Ye0  +  Ue_blue ) >> 16  ] 
                     |  ( color_table[ ( Ye0  +  UeVe_green ) >> 16 ] << 8  )
                     |  ( color_table[ ( Ye0  +  Ve_red ) >> 16 ] << 16  )
                     |  (  255 << 24 );
        ((TUInt32 * )pDst)[ 1 ] = color_table[ ( Ye1  +  Ue_blue ) >> 16  ] 
                     |  ( color_table[ ( Ye1  +  UeVe_green ) >> 16 ] << 8  )
                     |  ( color_table[ ( Ye1  +  Ve_red ) >> 16 ] << 16  )
                     |  (  255 << 24 );
    }

void  DECODE_YUYV_Common_line(TARGB32 *  pDstLine, const  TUInt8 *  pYUYV, long  width)
    {
         for  ( long  x = 0 ;x < width;x += 2 )
        {
            YUVToRGB32_Two( & pDstLine[x],pYUYV[ 0 ],pYUYV[ 2 ],pYUYV[ 1 ],pYUYV[ 3 ]);
            pYUYV += 4 ;
        }
    }

void  DECODE_YUYV_Common( const  TUInt8 *  pYUYV, const  TPicRegion &  DstPic)
{
    assert((DstPic.width  &   1 ) == 0 ); 
    
     long  YUV_byte_width = (DstPic.width >> 1 ) << 2 ;
    TARGB32 *  pDstLine = DstPic.pdata; 
     for  ( long  y = 0 ;y < DstPic.height; ++ y)
    {
        DECODE_YUYV_Common_line(pDstLine,pYUYV,DstPic.width);
        pYUYV += YUV_byte_width;
        ((TUInt8 *& )pDstLine) += DstPic.byte_width;
    }    
}

速度测试:

//==============================================================================
//                       |        1024x576       |       1920x1080       |
//------------------------------------------------------------------------------
//                       |  AMD64x2  |   Core2   |  AMD64x2  |   Core2   |
//------------------------------------------------------------------------------
//DECODE_YUYV_Common       250.7 FPS  287.1 FPS     71.9 FPS   80.7 FPS

H:把测试成绩放在一起

//测试平台:(CPU:AMD64x2 4200+(2.37G);   内存:DDR2 677(双通道); 编译器:VC2005)
//测试平台:(CPU:Intel Core2 4400(2.00G);内存:DDR2 667(双通道); 编译器:VC2005)

//==============================================================================
//                       |        1024x576       |       1920x1080       |
//------------------------------------------------------------------------------
//                       |  AMD64x2  |   Core2   |  AMD64x2  |   Core2   |
//------------------------------------------------------------------------------
//DECODE_YUYV_Float         55.0 FPS   63.7 FPS     15.6 FPS   18.0 FPS
//DECODE_YUYV_Int          137.1 FPS  131.9 FPS     39.0 FPS   37.1 FPS
//DECODE_YUYV_RGBTable     164.8 FPS  152.9 FPS     47.1 FPS   43.7 FPS
//DECODE_YUYV_Table        146.1 FPS  151.3 FPS     41.8 FPS   43.5 FPS
//DECODE_YUYV_TableEx      236.5 FPS  300.5 FPS     68.1 FPS   85.0 FPS
//DECODE_YUYV_Common       250.7 FPS  287.1 FPS     71.9 FPS   80.7 FPS

( 欢迎提出不足和改进意见; 下一篇文章将继续成倍的提高解码速度)

YUV视频格式到RGB32格式转换的速度优化 上篇(转)相关推荐

  1. YUV视频格式详解(翻译自微软文档)

    Video Rendering with 8-Bit YUV Formats Gary Sullivan 和 Stephen Estrop 微软数字媒体部门 四月 2002年 更新于 八月 2003 ...

  2. 音视频 yuv视频格式详解(一)

    引论 Yuv在流媒体领域是一个既熟悉又陌生的概念,在转码过程中需要将视频解码成yuv再重新编码以便更改一些参数, 也需要在yuv上做一些处理比如添加水印, 提升亮度,等等.之前也是使用没用重视这个格式 ...

  3. YUV格式学习:YUV444转换RGB24

    YUV格式有很多种,按其采样方式,有444.422.420,还有411(但不常见).针对数据的排序,又有平面格式和打包格式,还有"踢啊"特有的半平面格式--这些排列组合,就显得YU ...

  4. RMVB格式介绍,如何播放该格式视频,以及将RMVB转换成MP4?

    目录 一.什么是RMVB文件 二.可支持RMVB格式的播放器 三.将RMVB转换为MP4格式的原因与方法 一.什么是RMVB文件 RMVB(RealMedia Variable Bitrate),是由 ...

  5. 视频格式怎么转换,将mp4格式转为mov格式

    视频文件格式怎么转换?这是困扰了很多用户的常见问题之一,有没有什么比较好用的工具,可以将各种视频文件格式快速互相转换呢?小编今天为您带来不错的教程分享,话不多说,下面就来介绍一下! 第一步,运行软件[ ...

  6. SWF格式的视频如何快速无损地转换成MP4格式

    SWF格式是一个动画文件,被广泛应用于网页设计.动画制作等领域.有时候我们需要将我们制作好的SWF格式动画转换成MP4格式的视频.那么该如何进行转换呢?其实很简单.下面小编便来分享我们平时转换的方法给 ...

  7. 视频AVI如何批量快速转换成MP4格式

    可能现在大部分人拍摄或是下载的视频都是MP4格式的,但其实视频的格式有非常多种.最近我们公司的小王就有个困扰,他的客户给了他一些AVI格式的视频,他却打不开了不知道怎么处理.其实AVI是将语音和影像同 ...

  8. 视频里的音乐怎么转换成mp3格式?

    视频里的音乐怎么转换成mp3格式?视频里的音乐转换为mp3的原因有很多,主要是因为mp3格式是一种音频格式,文件大小较小,更易于存储和传输.相比之下,视频格式则是一种视频文件格式,虽然包含音频,但我们 ...

  9. 全能视频转换器,万能格式转换

    狸窝全能视频转换器是一款功能强大.界面友好的全能型音视频转换及编辑的万能格式转换工具.有了它,您可以在几乎所有流行的视频格式之间,任意相互转换.如:RM.RMVB.VOB.DAT.VCD.SVCD.A ...

最新文章

  1. 2022-2028年中国电容器用薄膜行业市场研究分析及投资前景展望报告
  2. 两个列表之间移动数据
  3. 海康威视连续采图与单步采图_c#
  4. 希尔排序之C++实现(高级版)
  5. QLineEdit学习
  6. python中读取文件编码_[转载]python中使用文件的读取编码问题
  7. Flask 中的Jinja2模板引擎
  8. 探求Floyd算法的动态规划本质
  9. 使用Python+pillow绘制矩阵盖尔圆
  10. 要想完全放弃Windows使用Linux需要多少勇气?
  11. 零基础学python-零基础如何开始学习 Python?看完这篇从小白变大牛!
  12. java servlet大学生旅游网站的设计与开发源码
  13. 青少年编程Playgrounds之一
  14. ubuntu流量监控_ubuntu 流量监控
  15. python3 列表list 内置函数
  16. 黑马程序员前端JavaScript高级——ES6学习笔记
  17. Firefox,火狐about:config设置详解
  18. mysql查询连续天数数据
  19. Java 使用 iText5 API 根据需求导出 PDF
  20. 如何在Adobe Illustrator中创建复古风格的室内场景

热门文章

  1. Java中 EvenQueue.invokeLater用法
  2. javascript基础学习(六)
  3. 大型网站系统架构演化之路(转)
  4. Windows UWP开发系列 – 3D变换
  5. 444牛X的日常口语
  6. 滑动门和翻转门实现的横竖双tab标签测试页面(附源码)
  7. 数据挖掘原理与算法:机器学习->{[sklearn. model_selection. train_test_split]、[h2o]、[网格搜索]、[numpy]、[plotly.express]}
  8. 对称加密算法_技术分享丨这是一篇简单的小科普——什么是对称加密算法?(下)...
  9. python __file__怎么实现_python lockfile(文件锁)
  10. 中画图title函数_MATLAB-基础画图meshgrid