明天回家啦,庆祝一下,贡献一段源码,基于linux V4L视频采集摄像程序

/*****************************************************************************************************

linux_m4v.c

gcc -o linux_m4v linux_m4v.c -lc -lm -lxvidcore

*******************************************************************************************************/

#include <string.h>
#include <sys/types.h>

#include <sys/stat.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <linux/videodev.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <signal.h>

#include "xvid_encode.h"
void *enc_handle = NULL;

int done = 0;
int
enc_main(unsigned char *image,
   unsigned char *bitstream,
   int *key,
   int *stats_type,
   int *stats_quant,
   int *stats_length,
   int sse[3]);
int
enc_stop();
int

enc_init(int use_assembler);
double
msecond();

 

 

#define VIDEO_PALETTE_JPEG  21

struct vdIn {
 int fd;
 char *videodevice ;
 struct video_capability videocap;
 struct video_picture videopict;
 struct video_window videowin;
 int framesizeIn ;
 int bppIn;
 int  hdrwidth;
 int  hdrheight;
 int  formatIn;
};

struct vdIn videoIn;
int init_videoIn (struct vdIn *vd, char *device, int width, int height,int format);
static int GetDepth (int format);
static int GetVideoPict (struct vdIn *vd);
static int SetVideoPict (struct vdIn *vd);


int main(int argc,char *argv[])
{
 char *device;
 
 int format = VIDEO_PALETTE_YUV420P;
 int width = 352;
   int height = 288;
 int i;
 unsigned char r_buffer[304128];
 unsigned char* mp4_buffer;

 double enctime;
 double totalenctime = 0.;
 float totalPSNR[3] = {0., 0., 0.};
 device = "/dev/video0";
 ARG_OUTPUTFILE = "test.m4v";
 int use_assembler = 1;
 int result;
 int totalsize;
 int m4v_size;
 int key;
 int stats_type;
 int stats_quant;
 int stats_length;
 int input_num;
 int output_num;

 char filename[256];
 FILE *out_file = NULL;

 memset (&videoIn, 0, sizeof (struct vdIn));
   if (init_videoIn(&videoIn, device, width, height,format) != 0)
       printf (" damned encore rate !!/n");
 /* xvid init */
 ARG_SAVEMPEGSTREAM = 1;
 ARG_SAVEINDIVIDUAL = 0;
 
 XDIM = width;
 YDIM = height;
 mp4_buffer = (unsigned char *) malloc(IMAGE_SIZE(XDIM, YDIM) * 2);
 
 totalsize = 0;

 result = 0;
 result = enc_init(0);
 if (result != 0) {
  fprintf(stderr, "Encore INIT problem, return value %d/n",result);
  goto release_all;
 }

/* i=read(videoIn.fd,r_buffer,304128);
 printf("i read : %d/n",i);
 if(i<0){
  printf("error read!/n");
  close(videoIn.fd);
  return -1;
  }
*/
 input_num = 0;    /* input frame counter */
 output_num = 0;


 
 if (ARG_SAVEMPEGSTREAM && ARG_OUTPUTFILE) {

  if ((out_file = fopen(ARG_OUTPUTFILE, "w+b")) == NULL) {
   fprintf(stderr, "Error opening output file %s/n", ARG_OUTPUTFILE);
   goto release_all;
  }

 } else {
  out_file = NULL;
 }
 
 

 /* Xvid encode */
 do {

  char *type;
  int sse[3];
  i=read(videoIn.fd,r_buffer,304128);
  printf("i read : %d/n",i);
  if(i<0){
   printf("error read!/n");
   close(videoIn.fd);
   return -1;
  }

  if (input_num >= ARG_MAXFRAMENR) {
   //result = 1;
   done = 1;
  }
  enctime = msecond();
  m4v_size =enc_main(!result ? (unsigned char*)r_buffer:0,mp4_buffer, &key, &stats_type,&stats_quant, &stats_length, sse);
  enctime = msecond() - enctime;
  printf("m4v_size is %d /n",m4v_size);
 if (m4v_size < 0) {
   printf("erro in encode..../n");
  }

  /* Update encoding time stats */
  totalenctime += enctime;
  totalsize += m4v_size;
 if (m4v_size > 0 && ARG_SAVEMPEGSTREAM) {

   /* Save single files */
   if (ARG_SAVEINDIVIDUAL) {
    FILE *out;
    sprintf(filename, "%sframe%05d.m4v", filepath, output_num);
    out = fopen(filename, "w+b");
    fwrite(mp4_buffer, m4v_size, 1, out);
    fclose(out);
    output_num++;
   }
   /* Save ES stream */
   if (ARG_OUTPUTFILE && out_file)
    fwrite(mp4_buffer, 1, m4v_size, out_file);
  }

  input_num++;


 } while (!done);


 
 if(m4v_size<0){
  printf("error write_jpeg!/n");
  close(videoIn.fd);
  fclose(out_file);
  return -1;
  }
 printf("OK./n");

release_all:

 if (enc_handle) {
  result = enc_stop();
  if (result)
   fprintf(stderr, "Encore RELEASE problem return value %d/n",
     result);
 }

 
 fclose(out_file);
 close(videoIn.fd);
 return 0;
}

int init_videoIn (struct vdIn *vd, char *device, int width, int height,
       int format)
{
 int erreur;
 vd->hdrwidth = width;
   vd->hdrheight = height;
   vd->formatIn = format;
   vd->bppIn = GetDepth (vd->formatIn);
 
 if ((vd->fd = open (device, O_RDWR)) == -1){
      printf("ERROR opening V4L interface/n");
  close(vd->fd);
  return -1;
  }
 if (ioctl (vd->fd, VIDIOCGCAP, &(vd->videocap)) == -1){
      printf("ERROR opening video_capability interface/n");
  close(vd->fd);
  return -1;
  }
   printf ("Camera found: %s /n", vd->videocap.name);

 erreur = GetVideoPict (vd);
 vd->videopict.palette = vd->formatIn;
   vd->videopict.depth = GetDepth (vd->formatIn);
   vd->bppIn = GetDepth (vd->formatIn);
 
    vd->framesizeIn = (vd->hdrwidth * vd->hdrheight * vd->bppIn) >> 3;
  
   erreur = SetVideoPict (vd);
   erreur = GetVideoPict (vd);
   if (vd->formatIn != vd->videopict.palette ||
        vd->bppIn != vd->videopict.depth){
      printf("ERROR set video_picture interface/n");
  close(vd->fd);
  return -1;
  }
   if (erreur < 0){
      printf("ERROR set palette /n");
  close(vd->fd);
  return -1;
  }
 if (ioctl (vd->fd, VIDIOCGWIN, &(vd->videowin)) < 0)
  perror ("VIDIOCGWIN failed /n");
       vd->videowin.height = vd->hdrheight;
      vd->videowin.width = vd->hdrwidth;
      if (ioctl (vd->fd, VIDIOCSWIN, &(vd->videowin)) < 0)
  perror ("VIDIOCSWIN failed /n");
 if (ioctl (vd->fd, VIDIOCGWIN, &(vd->videowin)) < 0)
  perror ("VIDIOCGWIN failed /n");
      printf ("VIDIOCSWIN height %d  width %d /n",
       vd->videowin.height, vd->videowin.width);
 return 0;
}

static int
GetDepth (int format)
{
  int depth;
  switch (format)
    {
  
   case VIDEO_PALETTE_JPEG:
      {
 depth = 8;  
      }
      break;
    case VIDEO_PALETTE_RAW:
      {
 depth = 8;  
      }
      break;
    case VIDEO_PALETTE_YUV420P:
      {
 //depth = (8 * 3) >> 1;
 depth = 24;
      }
      break;
    case VIDEO_PALETTE_RGB565:
      depth = 16;
      break;
    case VIDEO_PALETTE_RGB24:
      depth = 24;
      break;
    case VIDEO_PALETTE_RGB32:
      {
 depth = 32;
      }
      break;
    default:
      depth = -1;
      break;
    }
  return depth;
}

static int
GetVideoPict (struct vdIn *vd)
{
  if (ioctl (vd->fd, VIDIOCGPICT, &vd->videopict) < 0){
      printf("ERROR opening video_capability interface/n");
  close(vd->fd);
  return -1;
  }


  printf ("VIDIOCGPICT brightnes=%d hue=%d color=%d contrast=%d whiteness=%d"
   "depth=%d palette=%d/n", vd->videopict.brightness,
   vd->videopict.hue, vd->videopict.colour, vd->videopict.contrast,
   vd->videopict.whiteness, vd->videopict.depth,
   vd->videopict.palette);

  return 0;
}

static int
SetVideoPict (struct vdIn *vd)
{
  if (ioctl (vd->fd, VIDIOCSPICT, &vd->videopict) < 0){
      printf("ERROR set video_capability interface/n");
  close(vd->fd);
  return -1;
  }

  printf ("VIDIOCSPICT brightnes=%d hue=%d color=%d contrast=%d whiteness=%d"
   "depth=%d palette=%d/n", vd->videopict.brightness,
   vd->videopict.hue, vd->videopict.colour, vd->videopict.contrast,
   vd->videopict.whiteness, vd->videopict.depth,
   vd->videopict.palette);

  return 0;
}

double
msecond()
{

 struct timeval tv;

 gettimeofday(&tv, 0);
 return (tv.tv_sec * 1.0e3 + tv.tv_usec * 1.0e-3);

}

#define FRAMERATE_INCR 1001

int

enc_init(int use_assembler)

{

 int xerr;

 //xvid_plugin_cbr_t cbr;

     xvid_plugin_single_t single;

 xvid_plugin_2pass1_t rc2pass1;

 xvid_plugin_2pass2_t rc2pass2;

 //xvid_plugin_fixed_t rcfixed;

 xvid_enc_plugin_t plugins[7];

 xvid_gbl_init_t xvid_gbl_init;

 xvid_enc_create_t xvid_enc_create;

 

 /*------------------------------------------------------------------------

  * XviD core initialization

  *----------------------------------------------------------------------*/

 

 /* Set version -- version checking will done by xvidcore */

 memset(&xvid_gbl_init, 0, sizeof(xvid_gbl_init));

 xvid_gbl_init.version = XVID_VERSION;

     xvid_gbl_init.debug = 0;

 

 

 /* Do we have to enable ASM optimizations ? */

 if (use_assembler) {

  xvid_gbl_init.cpu_flags = 0;

 }

 

 /* Initialize XviD core -- Should be done once per __process__ */

 xvid_global(NULL, XVID_GBL_INIT, &xvid_gbl_init, NULL);

 

 /*------------------------------------------------------------------------

  * XviD encoder initialization

  *----------------------------------------------------------------------*/

 

 /* Version again */

 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 = XDIM;

 xvid_enc_create.height = YDIM;

 xvid_enc_create.profile = XVID_PROFILE_S_L3;

 

 /* init plugins  */

     xvid_enc_create.zones = NULL;

     xvid_enc_create.num_zones = 0;

 

 xvid_enc_create.plugins = NULL;

 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 */

 if ((ARG_FRAMERATE - (int) ARG_FRAMERATE) < SMALL_EPS) {

  xvid_enc_create.fincr = 1;

  xvid_enc_create.fbase = (int) ARG_FRAMERATE;

 } else {

  xvid_enc_create.fincr = FRAMERATE_INCR;

  xvid_enc_create.fbase = (int) (FRAMERATE_INCR * ARG_FRAMERATE);

 }

 

 /* Maximum key frame interval */

     if (ARG_MAXKEYINTERVAL > 0) {

         xvid_enc_create.max_key_interval = ARG_MAXKEYINTERVAL;

     }else {

      xvid_enc_create.max_key_interval = (int) ARG_FRAMERATE *10;

     }

 

 /* Bframes settings */

 xvid_enc_create.max_bframes = 0;

 xvid_enc_create.bquant_ratio = 150;

 xvid_enc_create.bquant_offset = 100;

 

 /* Dropping ratio frame -- we don't need that */

 xvid_enc_create.frame_drop_ratio = 0;

 

 /* Global encoder options */

 xvid_enc_create.global = 0;

 

 /* 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);

 

 /* Retrieve the encoder instance from the structure */

 enc_handle = xvid_enc_create.handle;

 

 return (xerr);

}

int
enc_stop()
{
 int xerr;

 /* Destroy the encoder instance */
 xerr = xvid_encore(enc_handle, XVID_ENC_DESTROY, NULL, NULL);

 return (xerr);
}

int
enc_main(unsigned char *image,
   unsigned char *bitstream,
   int *key,
   int *stats_type,
   int *stats_quant,
   int *stats_length,
   int sse[3])
{
 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 */
 if (image) {
  xvid_enc_frame.input.plane[0] = image;
#ifndef READ_PNM
  if (ARG_INPUTTYPE==2)
   xvid_enc_frame.input.csp = XVID_CSP_YV12;
  else
   xvid_enc_frame.input.csp = XVID_CSP_I420;
  xvid_enc_frame.input.stride[0] = XDIM;
#else
  xvid_enc_frame.input.csp = XVID_CSP_BGR;
  xvid_enc_frame.input.stride[0] = XDIM*3;
#endif
 } else {
  xvid_enc_frame.input.csp = XVID_CSP_NULL;
 }

 /* Set up core's general features */
 xvid_enc_frame.vol_flags = 0;
 if (ARG_STATS)
  xvid_enc_frame.vol_flags |= XVID_VOL_EXTRASTATS;
 if (ARG_QTYPE)
  xvid_enc_frame.vol_flags |= XVID_VOL_MPEGQUANT;
 if (ARG_QPEL)
  xvid_enc_frame.vol_flags |= XVID_VOL_QUARTERPEL;
 if (ARG_GMC)
  xvid_enc_frame.vol_flags |= XVID_VOL_GMC;
 if (ARG_INTERLACING)
  xvid_enc_frame.vol_flags |= XVID_VOL_INTERLACING;

 /* Set up core's general features */
 xvid_enc_frame.vop_flags = vop_presets[ARG_QUALITY];

    if (ARG_VOPDEBUG) {
        xvid_enc_frame.vop_flags |= XVID_VOP_DEBUG;
    }

    if (ARG_GREYSCALE) {
        xvid_enc_frame.vop_flags |= XVID_VOP_GREYSCALE;
    }

 /* 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];

 if (ARG_GMC)
  xvid_enc_frame.motion |= XVID_ME_GME_REFINE;

 if (ARG_QPEL)
  xvid_enc_frame.motion |= XVID_ME_QUARTERPELREFINE16;
 if (ARG_QPEL && (xvid_enc_frame.vop_flags & XVID_VOP_INTER4V))
  xvid_enc_frame.motion |= XVID_ME_QUARTERPELREFINE8;

 if (ARG_TURBO)
  xvid_enc_frame.motion |= XVID_ME_FASTREFINE16 | XVID_ME_FASTREFINE8 |
         XVID_ME_SKIP_DELTASEARCH | XVID_ME_FAST_MODEINTERPOLATE |
         XVID_ME_BFRAME_EARLYSTOP;

 if (ARG_BVHQ)
  xvid_enc_frame.vop_flags |= XVID_VOP_RD_BVOP;

 switch (ARG_VHQMODE) /* this is the same code as for vfw */
 {
 case 1: /* VHQ_MODE_DECISION */
  xvid_enc_frame.vop_flags |= XVID_VOP_MODEDECISION_RD;
  break;

 case 2: /* VHQ_LIMITED_SEARCH */
  xvid_enc_frame.vop_flags |= XVID_VOP_MODEDECISION_RD;
  xvid_enc_frame.motion |= XVID_ME_HALFPELREFINE16_RD;
  xvid_enc_frame.motion |= XVID_ME_QUARTERPELREFINE16_RD;
  break;

 case 3: /* VHQ_MEDIUM_SEARCH */
  xvid_enc_frame.vop_flags |= XVID_VOP_MODEDECISION_RD;
  xvid_enc_frame.motion |= XVID_ME_HALFPELREFINE16_RD;
  xvid_enc_frame.motion |= XVID_ME_HALFPELREFINE8_RD;
  xvid_enc_frame.motion |= XVID_ME_QUARTERPELREFINE16_RD;
  xvid_enc_frame.motion |= XVID_ME_QUARTERPELREFINE8_RD;
  xvid_enc_frame.motion |= XVID_ME_CHECKPREDICTION_RD;
  break;

 case 4: /* VHQ_WIDE_SEARCH */
  xvid_enc_frame.vop_flags |= XVID_VOP_MODEDECISION_RD;
  xvid_enc_frame.motion |= XVID_ME_HALFPELREFINE16_RD;
  xvid_enc_frame.motion |= XVID_ME_HALFPELREFINE8_RD;
  xvid_enc_frame.motion |= XVID_ME_QUARTERPELREFINE16_RD;
  xvid_enc_frame.motion |= XVID_ME_QUARTERPELREFINE8_RD;
  xvid_enc_frame.motion |= XVID_ME_CHECKPREDICTION_RD;
  xvid_enc_frame.motion |= XVID_ME_EXTSEARCH_RD;
  break;

 default :
  break;
 }
   
 if (ARG_QMATRIX) {
  /* We don't use special matrices */
  xvid_enc_frame.quant_intra_matrix = qmatrix_intra;
  xvid_enc_frame.quant_inter_matrix = qmatrix_inter;
 }
 else {
  /* 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(enc_handle, XVID_ENC_ENCODE, &xvid_enc_frame,
       &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);
}

 /********************************xvid_encode.h**********************************/

#ifndef XVID_ENCODE_H
#define XVID_ENCODE_H
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>

#include <sys/time.h>

#include "xvid.h"

#define ABS_MAXFRAMENR 9999

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]))


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 XDIM = 0;
static int YDIM = 0;
static int ARG_BQRATIO = 150;
static int ARG_BQOFFSET = 100;
static int ARG_MAXBFRAMES = 0;
static int ARG_PACKED = 0;
static int ARG_DEBUG = 0;
static int ARG_VOPDEBUG = 0;
static int ARG_GREYSCALE = 0;
static int ARG_QTYPE = 0;
static int ARG_QMATRIX = 0;
static int ARG_GMC = 0;
static int ARG_INTERLACING = 0;
static int ARG_QPEL = 0;
static int ARG_TURBO = 0;
static int ARG_VHQMODE = 0;
static int ARG_BVHQ = 0;
static int ARG_CLOSED_GOP = 0;

#define MAX_ZONES   64

static xvid_enc_zone_t ZONES[MAX_ZONES];
static int NUM_ZONES = 0;

#define SMALL_EPS (1e-10)
#define FRAMERATE_INCR 1001

static unsigned char qmatrix_intra[64];
static unsigned char qmatrix_inter[64];

static char filepath[256] = "./";

#define IMAGE_SIZE(x,y) ((x)*(y)*3/2)

 

#endif

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值