LinuxSir.cn,穿越时空的Linuxsir!

 找回密码
 注册
搜索
热搜: shell linux mysql
查看: 10847|回复: 26

贡献出LINUX MPEG4 DVR源代码给SIR,另外还包括一个可以跨平台运行的MPEG4 播放器

[复制链接]
发表于 2005-4-11 20:47:24 | 显示全部楼层 |阅读模式
版权声明:
本代码版权属于本人,您可以在遵循GPL授权的条件下加以使用。
一.LINUX DVR源码

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <stdint.h>
  4. #include <errno.h>
  5. #include <fcntl.h>
  6. #include <signal.h>
  7. #include <sys/ioctl.h>
  8. #include <sys/mman.h>
  9. #include <linux/videodev.h>
  10. #include "xvid.h"
  11. #define FRAMERATE_INCR 1001
  12. #define SMALL_EPS (1e-10)
  13. #define VIDEO "/dev/video"
  14. #define INDEX 0
  15. #define IOCTL(fd, req, addr ) \
  16. ((-1==ioctl(fd,req,addr))?(perror(#req),close(fd),exit(EXIT_FAILURE)):0)

  17. static float ARG_FRAMERATE = 25.00f;
  18. static int ARG_QUALITY = 4;
  19. static int ARG_MAXKEYINTERVAL = 250;
  20. static char * ARG_OUTPUTFILE= "out.m4u";
  21. static FILE * fp = NULL;
  22. static int done = 0;
  23. static const int motion_presets[] = {
  24.         /* quality 0 */
  25.         0,

  26.         /* quality 1 */
  27.         XVID_ME_ADVANCEDDIAMOND16,

  28.         /* quality 2 */
  29.         XVID_ME_ADVANCEDDIAMOND16 | XVID_ME_HALFPELREFINE16,

  30.         /* quality 3 */
  31.         XVID_ME_ADVANCEDDIAMOND16 | XVID_ME_HALFPELREFINE16 |
  32.         XVID_ME_ADVANCEDDIAMOND8 | XVID_ME_HALFPELREFINE8,

  33.         /* quality 4 */
  34.         XVID_ME_ADVANCEDDIAMOND16 | XVID_ME_HALFPELREFINE16 |
  35.         XVID_ME_ADVANCEDDIAMOND8 | XVID_ME_HALFPELREFINE8 |
  36.         XVID_ME_CHROMA_PVOP | XVID_ME_CHROMA_BVOP,

  37.         /* quality 5 */
  38.         XVID_ME_ADVANCEDDIAMOND16 | XVID_ME_HALFPELREFINE16 |
  39.         XVID_ME_ADVANCEDDIAMOND8 | XVID_ME_HALFPELREFINE8 |
  40.         XVID_ME_CHROMA_PVOP | XVID_ME_CHROMA_BVOP,

  41.         /* quality 6 */
  42.         XVID_ME_ADVANCEDDIAMOND16 | XVID_ME_HALFPELREFINE16 | XVID_ME_EXTSEARCH16 |
  43.         XVID_ME_ADVANCEDDIAMOND8 | XVID_ME_HALFPELREFINE8 | XVID_ME_EXTSEARCH8 |
  44.         XVID_ME_CHROMA_PVOP | XVID_ME_CHROMA_BVOP,

  45. };
  46. static const int vop_presets[] = {
  47.         /* quality 0 */
  48.         0,

  49.         /* quality 1 */
  50.         0,

  51.         /* quality 2 */
  52.         XVID_VOP_HALFPEL,

  53.         /* quality 3 */
  54.         XVID_VOP_HALFPEL | XVID_VOP_INTER4V,

  55.         /* quality 4 */
  56.         XVID_VOP_HALFPEL | XVID_VOP_INTER4V,

  57.         /* quality 5 */
  58.         XVID_VOP_HALFPEL | XVID_VOP_INTER4V |
  59.         XVID_VOP_TRELLISQUANT,

  60.         /* quality 6 */
  61.         XVID_VOP_HALFPEL | XVID_VOP_INTER4V |
  62.         XVID_VOP_TRELLISQUANT | XVID_VOP_HQACPRED,

  63. };

  64. static int XDIM=352,YDIM=288;
  65. static use_assembler = 0;
  66. static void *enc_handle = NULL;

  67. static int enc_init(int use_assembler);
  68. static int enc_main(unsigned char *image,
  69.                                         unsigned char *bitstream,
  70.                                         int *key,
  71.                                         int *stats_type,
  72.                                         int *stats_quant,
  73.                                         int *stats_length,
  74.                                         int stats[3]);
  75. static int enc_stop();
  76. //signal act method defination
  77. static void clean(int signum)
  78. {
  79.     done=1;
  80. }
  81. int
  82. main(int argc,char *argv[])
  83. {
  84.     //register SIGINT action method ,to save the m4u file
  85.     signal(SIGINT,clean);
  86.     int fd;
  87.     struct v4l2_capability cap;   
  88.     struct v4l2_format format;
  89.     struct v4l2_requestbuffers reqbuf;
  90.     struct v4l2_buffer buffer;
  91.     struct v4l2_input input;
  92.     int index=0,i;
  93.         for (i=1; i< argc; i++) {

  94.                 if (strcmp("-asm", argv[i]) == 0 ) {
  95.                         use_assembler = 1;
  96.                 }else if(strcmp("-f", argv[i]) == 0 && i < argc -1){
  97.             i++;
  98.             ARG_OUTPUTFILE = argv[i];
  99.         }else if(strcmp("-i", argv[i]) == 0 && i < argc -1){
  100.             i++;
  101.             index = atoi(argv[i]);
  102.         } else if(strcmp("-w", argv[i]) == 0 && i < argc -1){
  103.             i++;
  104.             XDIM = atoi(argv[i]);
  105.         } else if(strcmp("-h", argv[i]) == 0 && i < argc -1){
  106.             i++;
  107.             YDIM = atoi(argv[i]);
  108.         }
  109.         }
  110.    
  111.         //init capture card
  112.    
  113.     fd = open(VIDEO,O_RDWR);
  114.     if(fd<0)
  115.     {
  116.         perror("Can't open /dev/video device");
  117.         exit(errno);
  118.     }
  119.     //if card can't support video capture and by means of steamio,exit
  120.    
  121.     IOCTL(fd, VIDIOC_QUERYCAP, &cap);
  122.     if ( !(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)
  123.          &&!(cap.capabilities & V4L2_CAP_STREAMING))
  124.     {
  125.         fprintf(stderr, "Couldn't use the card \n");
  126.         exit(3);
  127.     }               
  128.    
  129.         //query input and select the desired input
  130.        
  131.         IOCTL(fd, VIDIOC_G_INPUT, &index);
  132.     input.index = index;
  133.     IOCTL(fd, VIDIOC_ENUMINPUT, &input);
  134.     printf ("Current input: Index %i,Name %s\n", index,input.name);   
  135.     for(i=0;;i++)
  136.     {
  137.         if(i!=index)
  138.         {
  139.             input.index = i;
  140.             if(-1==ioctl(fd, VIDIOC_ENUMINPUT, &input))
  141.                 break;
  142.             else
  143.                 printf ("Other input: Index %i,Name %s\n",i,input.name);
  144.         }
  145.     }
  146.         IOCTL(fd, VIDIOC_S_INPUT, &index);
  147.        
  148.     //get current video format,set the desired format
  149.    
  150.     format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  151.     IOCTL(fd,VIDIOC_G_FMT,&format);
  152.     format.fmt.pix.width = XDIM;
  153.     format.fmt.pix.height = YDIM;
  154.     format.fmt.pix.pixelformat = V4L2_PIX_FMT_YVU420;
  155.     format.fmt.pix.field = V4L2_FIELD_ANY;//V4L2_FIELD_INTERLACED
  156.    
  157.         IOCTL(fd,VIDIOC_S_FMT,&format);

  158.     XDIM = format.fmt.pix.width;
  159.     printf("Gotten width %d\n",XDIM);
  160.     YDIM = format.fmt.pix.height;
  161.     printf("Gotten height %d\n",YDIM);
  162.    
  163.         //let driver get the buffers
  164.    
  165.     reqbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  166.     reqbuf.memory = V4L2_MEMORY_MMAP;
  167.     reqbuf.count = 4;
  168.     IOCTL(fd,VIDIOC_REQBUFS,&reqbuf );
  169.     if (reqbuf.count < 4)
  170.     {
  171.        printf ("Not enough buffer memory for driver\n");
  172.        exit (5);
  173.     }

  174. //mmap the driver's buffer to application address
  175.    
  176.     //create relative buffers struct to be used by mmap

  177.     struct
  178.     {
  179.         void * start;
  180.         size_t length;
  181.     } buffers[reqbuf.count];
  182.    
  183.         //mmap the driver's kernel buffer into application
  184.        
  185.         for (i=0;i<reqbuf.count;i++)
  186.     {
  187.         buffer.type = reqbuf.type;
  188.         buffer.index =i ;
  189.         
  190.         //query the status of one buffer ,mmap the driver buffer
  191.         
  192.         IOCTL(fd,VIDIOC_QUERYBUF,&buffer);
  193.         buffers[i].length = buffer.length;
  194.         buffers[i].start = mmap (NULL,buffer.length,
  195.                                  PROT_READ | PROT_WRITE,
  196.                                  MAP_SHARED,
  197.                                  fd,buffer.m.offset);
  198.         if (buffers[i].start == MAP_FAILED)
  199.         {
  200.            close(fd);
  201.            perror ("mmap");
  202.            exit(errno);
  203.         }
  204.     }
  205.     //begin video capture
  206.    
  207.     IOCTL(fd,VIDIOC_STREAMON,&reqbuf.type);         
  208.    
  209.     //enqueue all driver buffers
  210.     for (i=0;i<reqbuf.count;i++)
  211.     {        
  212.         buffer.type = reqbuf.type;
  213.         buffer.index = i;
  214.         IOCTL(fd,VIDIOC_QUERYBUF, &buffer);
  215.         IOCTL(fd,VIDIOC_QBUF,&buffer);
  216.     }
  217.     //init xvid
  218.    
  219.     int result;
  220.     result = enc_init(1);
  221.     if(result!=0)
  222.     {
  223.         fprintf(stderr, "Encore INIT problem, return value %d\n", result);
  224.         goto clean_all;           
  225.     }
  226.    
  227.     //get mem of mpg4 frame
  228.    
  229.     uint8_t *mp4_buffer = NULL;   
  230.         mp4_buffer = (unsigned char *) malloc(XDIM*YDIM);
  231.         if (mp4_buffer==NULL)
  232.     {
  233.         fprintf(stderr,"malloc error");
  234.         goto clean_all;
  235.     }
  236.            int key;
  237.         int stats_type;
  238.         int stats_quant;
  239.         int stats_length;
  240.     int sse[3];            
  241.    
  242.         //create store mp4 file
  243.        
  244.         fp= fopen(ARG_OUTPUTFILE, "rb");
  245.     if (fp== NULL) {
  246.             perror("Error opening output file.");
  247.                 exit(-1);
  248.     }                

  249. //main loop ,frame capture,compressed

  250.     i = 0;
  251.     int outbytes,m4v_size;
  252.     while(!done)
  253.     {
  254.         //dequeue one frame
  255.             
  256.         buffer.type = reqbuf.type;
  257.         buffer.index = i;
  258.         IOCTL(fd, VIDIOC_QUERYBUF, &buffer);
  259.         IOCTL(fd, VIDIOC_DQBUF, &buffer);
  260.         /*debug info
  261.         printf("current frame's unix time seconds :%d\n",buffer.timestamp.tv_sec);
  262.         printf("current frame's unix time mcicoseconds :%d\n",buffer.timestamp.tv_usec);
  263.         */
  264.       
  265.         //compress a frame
  266.         
  267.         m4v_size = enc_main((uint8_t *)buffers[i].start,
  268.                              mp4_buffer+16,
  269.                              &key, &stats_type,&stats_quant, &stats_length, sse);
  270.                
  271.                 //store into output file
  272.                 outbytes = fwrite(mp4_buffer, 1, m4v_size, fp);
  273.                 if(outbytes != m4v_size)
  274.                 {
  275.                     fprintf(stderr,"Error writing the m4u file\n");
  276.                     exit(7);
  277.                 }
  278.                
  279.                 //enqueue one frame
  280.             
  281.         buffer.type = reqbuf.type;
  282.         buffer.index = i;
  283.         IOCTL(fd, VIDIOC_QUERYBUF, &buffer );
  284.         IOCTL(fd, VIDIOC_QBUF, &buffer );
  285.         i++;            
  286.         if( i >= reqbuf.count )
  287.             i = 0;
  288.     }
  289. clean_all:
  290.     fclose(fp);
  291.         enc_stop();   
  292.     //stop capture
  293.     IOCTL(fd, VIDIOC_STREAMOFF, &reqbuf.type );
  294.     //unmmap the apllication buffer
  295.     for (i=0;i<reqbuf.count;i++)
  296.         munmap (buffers[i].start,buffers[i].length);   
  297.     //release the dynamic mem
  298.     close(fd);
  299.         return 0;
  300. }

  301. int
  302. enc_init(int use_assembler)
  303. {
  304.         int xerr;
  305.         //xvid_plugin_cbr_t cbr;
  306.     xvid_plugin_single_t single;
  307.         xvid_plugin_2pass1_t rc2pass1;
  308.         xvid_plugin_2pass2_t rc2pass2;
  309.         //xvid_plugin_fixed_t rcfixed;
  310.         xvid_enc_plugin_t plugins[7];
  311.         xvid_gbl_init_t xvid_gbl_init;
  312.         xvid_enc_create_t xvid_enc_create;

  313.         /*------------------------------------------------------------------------
  314.          * XviD core initialization
  315.          *----------------------------------------------------------------------*/

  316.         /* Set version -- version checking will done by xvidcore */
  317.         memset(&xvid_gbl_init, 0, sizeof(xvid_gbl_init));
  318.         xvid_gbl_init.version = XVID_VERSION;
  319.     xvid_gbl_init.debug = 0;


  320.         /* Do we have to enable ASM optimizations ? */
  321.         if (use_assembler) {
  322.                 xvid_gbl_init.cpu_flags = 0;
  323.         }

  324.         /* Initialize XviD core -- Should be done once per __process__ */
  325.         xvid_global(NULL, XVID_GBL_INIT, &xvid_gbl_init, NULL);

  326.         /*------------------------------------------------------------------------
  327.          * XviD encoder initialization
  328.          *----------------------------------------------------------------------*/

  329.         /* Version again */
  330.         memset(&xvid_enc_create, 0, sizeof(xvid_enc_create));
  331.         xvid_enc_create.version = XVID_VERSION;

  332.         /* Width and Height of input frames */
  333.         xvid_enc_create.width = XDIM;
  334.         xvid_enc_create.height = YDIM;
  335.         xvid_enc_create.profile = XVID_PROFILE_S_L3;

  336.         /* init plugins  */
  337.     xvid_enc_create.zones = NULL;
  338.     xvid_enc_create.num_zones = 0;

  339.         xvid_enc_create.plugins = NULL;
  340.         xvid_enc_create.num_plugins = 0;

  341.         /* No fancy thread tests */
  342.         xvid_enc_create.num_threads = 0;

  343.         /* Frame rate - Do some quick float fps = fincr/fbase hack */
  344.         if ((ARG_FRAMERATE - (int) ARG_FRAMERATE) < SMALL_EPS) {
  345.                 xvid_enc_create.fincr = 1;
  346.                 xvid_enc_create.fbase = (int) ARG_FRAMERATE;
  347.         } else {
  348.                 xvid_enc_create.fincr = FRAMERATE_INCR;
  349.                 xvid_enc_create.fbase = (int) (FRAMERATE_INCR * ARG_FRAMERATE);
  350.         }

  351.         /* Maximum key frame interval */
  352.     if (ARG_MAXKEYINTERVAL > 0) {
  353.         xvid_enc_create.max_key_interval = ARG_MAXKEYINTERVAL;
  354.     }else {
  355.             xvid_enc_create.max_key_interval = (int) ARG_FRAMERATE *10;
  356.     }

  357.         /* Bframes settings */
  358.         xvid_enc_create.max_bframes = 0;
  359.         xvid_enc_create.bquant_ratio = 150;
  360.         xvid_enc_create.bquant_offset = 100;

  361.         /* Dropping ratio frame -- we don't need that */
  362.         xvid_enc_create.frame_drop_ratio = 0;

  363.         /* Global encoder options */
  364.         xvid_enc_create.global = 0;

  365.         /* I use a small value here, since will not encode whole movies, but short clips */
  366.         xerr = xvid_encore(NULL, XVID_ENC_CREATE, &xvid_enc_create, NULL);

  367.         /* Retrieve the encoder instance from the structure */
  368.         enc_handle = xvid_enc_create.handle;

  369.         return (xerr);
  370. }

  371. int
  372. enc_main(unsigned char *image,
  373.                  unsigned char *bitstream,
  374.                  int *key,
  375.                  int *stats_type,
  376.                  int *stats_quant,
  377.                  int *stats_length,
  378.                  int sse[3])
  379. {
  380.         int ret;

  381.         xvid_enc_frame_t xvid_enc_frame;
  382.         xvid_enc_stats_t xvid_enc_stats;

  383.         /* Version for the frame and the stats */
  384.         memset(&xvid_enc_frame, 0, sizeof(xvid_enc_frame));
  385.         xvid_enc_frame.version = XVID_VERSION;

  386.         memset(&xvid_enc_stats, 0, sizeof(xvid_enc_stats));
  387.         xvid_enc_stats.version = XVID_VERSION;

  388.         /* Bind output buffer */
  389.         xvid_enc_frame.bitstream = bitstream;
  390.         xvid_enc_frame.length = -1;

  391.         /* Initialize input image fields */
  392.         if (image) {
  393.                 xvid_enc_frame.input.plane[0] = image;
  394.                 xvid_enc_frame.input.csp = XVID_CSP_I420;
  395.                 xvid_enc_frame.input.stride[0] = XDIM;
  396.         } else {
  397.                 xvid_enc_frame.input.csp = XVID_CSP_NULL;
  398.         }

  399.         /* Set up core's general features */
  400.         xvid_enc_frame.vol_flags = 0;

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

  403.         /* Frame type -- let core decide for us */
  404.         xvid_enc_frame.type = XVID_TYPE_AUTO;

  405.         /* Force the right quantizer -- It is internally managed by RC plugins */
  406.         xvid_enc_frame.quant = 3;

  407.         /* Set up motion estimation flags */
  408.         xvid_enc_frame.motion = motion_presets[ARG_QUALITY];

  409.         /* We don't use special matrices */
  410.         xvid_enc_frame.quant_intra_matrix = NULL;
  411.         xvid_enc_frame.quant_inter_matrix = NULL;

  412.         /* Encode the frame */
  413.         ret = xvid_encore(enc_handle, XVID_ENC_ENCODE, &xvid_enc_frame,
  414.                                           &xvid_enc_stats);

  415.         *key = (xvid_enc_frame.out_flags & XVID_KEYFRAME);
  416.         *stats_type = xvid_enc_stats.type;
  417.         *stats_quant = xvid_enc_stats.quant;
  418.         *stats_length = xvid_enc_stats.length;
  419.         sse[0] = xvid_enc_stats.sse_y;
  420.         sse[1] = xvid_enc_stats.sse_u;
  421.         sse[2] = xvid_enc_stats.sse_v;
  422.         return (ret);
  423. }

  424. int
  425. enc_stop()
  426. {
  427.         int xerr;

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

  430.         return (xerr);
  431. }                                                                          
  432.                                                  

复制代码
 楼主| 发表于 2005-4-11 20:51:46 | 显示全部楼层
下面是基于SDL的跨平台MPEG4播放器源代码,支持硬件YUV加速

  1. #include <stdint.h>
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #include <string.h>
  5. #include <time.h>
  6. #include <SDL/SDL.h>
  7. #include "xvid.h"

  8. #define USE_PNM 1
  9. #define USE_TGA 0

  10. static int SHXDIM = 0;//display size
  11. static int SHYDIM = 0;
  12. static int XDIM = 352;//real size
  13. static int YDIM = 288;
  14. static int ARG_SAVEDECOUTPUT = 0;
  15. static int ARG_SAVEMPEGSTREAM = 0;
  16. static char *ARG_INPUTFILE = NULL;
  17. static int CSP = XVID_CSP_I420;
  18. static int BPP = 1;
  19. static int FORMAT = USE_PNM;
  20. static char filepath[256] = "./";
  21. static void *dec_handle = NULL;
  22. #define BUFFER_SIZE (2*1024*1024)
  23. static const int display_buffer_bytes = 0;
  24. static SDL_Surface *screen;
  25. static SDL_Overlay *overlay;
  26. static SDL_Rect rect;
  27. static double msecond();
  28. static int dec_init(int use_assembler, int debug_level);
  29. static int dec_main(unsigned char *istream,
  30.                                         unsigned char *ostream,
  31.                                         int istream_size,
  32.                                         xvid_dec_stats_t *xvid_dec_stats);
  33. static int dec_stop();
  34. static void usage();
  35. static int write_image(char *prefix, unsigned char *image);
  36. static int write_pnm(char *filename, unsigned char *image);
  37. static int write_tga(char *filename, unsigned char *image);
  38. const char * type2str(int type)
  39. {
  40.     if (type==XVID_TYPE_IVOP)
  41.         return "I";
  42.     if (type==XVID_TYPE_PVOP)
  43.         return "P";
  44.     if (type==XVID_TYPE_BVOP)
  45.         return "B";
  46.     return "S";
  47. }

  48. static void init_SDL()
  49. {
  50.     if (SDL_Init (SDL_INIT_VIDEO) < 0)
  51.     {
  52.         fprintf (stderr, "Couldn't initialize SDL: %s\n", SDL_GetError());
  53.         exit (1);
  54.     }
  55.     atexit (SDL_Quit);
  56.     screen = SDL_SetVideoMode (SHXDIM, SHYDIM, 0, SDL_HWSURFACE
  57.                                           | SDL_DOUBLEBUF
  58.                                           | SDL_ANYFORMAT
  59.                                           | SDL_RESIZABLE);
  60.     if (screen == NULL)
  61.     {
  62.         fprintf(stderr, "Couldn't set video mode: %s\n", SDL_GetError());
  63.         exit(2);
  64.     }
  65.     if (0 == screen->flags & SDL_HWSURFACE)
  66.     {
  67.         fprintf(stderr,"Can't get hardware surface\n");
  68.         exit(3);
  69.     }
  70.     SDL_WM_SetCaption ("SDL MultiMedia Application", NULL);      
  71.     overlay = SDL_CreateYUVOverlay(XDIM, YDIM, SDL_YV12_OVERLAY, screen);
  72.     if (!overlay)
  73.     {
  74.         fprintf(stderr, "Couldn't create overlay: %s\n", SDL_GetError());
  75.         exit(4);
  76.     }   
  77.     //show the overlay status
  78.     printf("Created %dx%dx%d %s %s overlay\n",overlay->w,overlay->h,overlay->planes,
  79.            overlay->hw_overlay?"hardware":"software",
  80.            overlay->format==SDL_YV12_OVERLAY?"YV12":
  81.            overlay->format==SDL_IYUV_OVERLAY?"IYUV":
  82.            overlay->format==SDL_YUY2_OVERLAY?"YUY2":
  83.            overlay->format==SDL_UYVY_OVERLAY?"UYVY":
  84.            overlay->format==SDL_YVYU_OVERLAY?"YVYU":
  85.            "Unknown");
  86.     rect.x=0;
  87.     rect.y=0;
  88.     rect.w=SHXDIM;
  89.     rect.h=SHYDIM;
  90. }

  91. int main(int argc, char *argv[])
  92. {
  93.         SDL_Event event;
  94.         uint32_t lastftick;
  95.         unsigned char *mp4_buffer = NULL;
  96.         unsigned char *mp4_ptr    = NULL;
  97.         unsigned char *out_buffer = NULL;
  98.         int useful_bytes;
  99.         xvid_dec_stats_t xvid_dec_stats;
  100.        
  101.         double totaldectime;
  102.   
  103.         long totalsize;
  104.         int status;
  105.         int fps = 25;
  106.     int fpsdelay;
  107.         int paused=0;
  108.     int resized=0;  
  109.         int use_assembler = 1;
  110.         int debug_level = 0;
  111.   
  112.         char filename[256];
  113.   
  114.         FILE *in_file;
  115.         int filenr;
  116.         int i;

  117.         for (i=1; i< argc; i++) {

  118.                 if (strcmp("-asm", argv[i]) == 0 ) {
  119.                         use_assembler = 1;
  120.                 } else if (strcmp("-debug", argv[i]) == 0 && i < argc - 1 ) {
  121.                         i++;
  122.                         if (sscanf(argv[i], "0x%x", &debug_level) != 1) {
  123.                                 debug_level = atoi(argv[i]);
  124.                         }
  125.                 } else if (strcmp("-d", argv[i]) == 0) {
  126.                         ARG_SAVEDECOUTPUT = 1;
  127.                 } else if (strcmp("-i", argv[i]) == 0 && i < argc - 1 ) {
  128.                         i++;
  129.                         ARG_INPUTFILE = argv[i];
  130.                 } else if (strcmp("-c", argv[i]) == 0  && i < argc - 1 ) {
  131.                         i++;
  132.                         if (strcmp(argv[i], "rgb16") == 0) {
  133.                                 CSP = XVID_CSP_RGB555;
  134.                                 BPP = 2;
  135.                         } else if (strcmp(argv[i], "rgb24") == 0) {
  136.                                 CSP = XVID_CSP_BGR;
  137.                                 BPP = 3;
  138.                         } else if (strcmp(argv[i], "rgb32") == 0) {
  139.                                 CSP = XVID_CSP_BGRA;
  140.                                 BPP = 4;
  141.                         } else if (strcmp(argv[i], "yv12") == 0) {
  142.                                 CSP = XVID_CSP_YV12;
  143.                                 BPP = 1;
  144.                         } else {
  145.                                 CSP = XVID_CSP_I420;
  146.                                 BPP = 1;
  147.                         }
  148.                 } else if (strcmp("-f", argv[i]) == 0 && i < argc -1) {
  149.                         i++;
  150.                         if (strcmp(argv[i], "tga") == 0) {
  151.                                 FORMAT = USE_TGA;
  152.                         } else {
  153.                                 FORMAT = USE_PNM;
  154.                         }
  155.                 } else if (strcmp("-help", argv[i]) == 0) {
  156.                         usage();
  157.                         return(0);
  158.                 } else if(strcmp("-w", argv[i]) == 0 && i < argc -1){
  159.             i++;
  160.             SHXDIM = atoi(argv[i]);
  161.         } else if(strcmp("-h", argv[i]) == 0 && i < argc -1){
  162.             i++;
  163.             SHYDIM = atoi(argv[i]);
  164.         } else if(strcmp("-fps", argv[i]) == 0 && i < argc -1){
  165.             i++;
  166.             fps = atoi(argv[i]);
  167.         }  
  168.         else {
  169.                         usage();
  170.                         exit(-1);
  171.                 }
  172.         }
  173.   
  174.         if (ARG_INPUTFILE==NULL) {
  175.                 fprintf(stderr, "Warning: MSVC build does not read EOF correctly from stdin. Use the -i switch.\n\n");
  176.         }
  177.     in_file = fopen(ARG_INPUTFILE, "rb");
  178.     if (in_file == NULL) {
  179.                         fprintf(stderr, "Error opening input file %s\n", ARG_INPUTFILE);
  180.                         return(-1);
  181.     }

  182.         /* PNM/PGM format can't handle 16/32 bit data */
  183.         if (BPP != 1 && BPP != 3 && FORMAT == USE_PNM) {
  184.                 FORMAT = USE_TGA;
  185.         }

  186.         /* Memory for encoded mp4 stream */
  187.         mp4_buffer = (unsigned char *) malloc(BUFFER_SIZE);
  188.         if (!mp4_buffer)
  189.                 goto free_all_memory;
  190.         out_buffer = (unsigned char *)malloc(XDIM*YDIM*3/2);
  191.         if (!out_buffer)
  192.                 goto free_all_memory;       
  193. /******************************************************************************
  194. *        INIT SDL
  195. *******************************************************************************/        
  196.     init_SDL();   

  197.         
  198. /*****************************************************************************
  199. *        XviD PART  Start
  200. ****************************************************************************/

  201.         status = dec_init(use_assembler, debug_level);
  202.         if (status) {
  203.                 fprintf(stderr,
  204.                                 "Decore INIT problem, return value %d\n", status);
  205.                 goto release_all;
  206.         }        

  207. /*****************************************************************************
  208. *                                 Main loop
  209. ****************************************************************************/

  210.         /* Fill the buffer ,create 2M buffer*/
  211.         useful_bytes = fread(mp4_buffer, 1, BUFFER_SIZE, in_file);

  212.         totaldectime = 0;
  213.         totalsize = 0;
  214.         filenr = 0;
  215.         mp4_ptr = mp4_buffer;
  216.     uint8_t  *outy,*outu,*outv,*op[3];
  217.         int y;
  218.     /* set the start frame */
  219.     i=0;
  220.     fpsdelay=1000/fps;

  221.         lastftick=SDL_GetTicks();       
  222.         do
  223.         {               
  224.                 int used_bytes = 0;
  225.                 double dectime;
  226.                 while (SDL_PollEvent(&event))
  227.         {
  228.             switch (event.type)
  229.             {
  230.                 case SDL_VIDEORESIZE:
  231.                      screen=SDL_SetVideoMode(event.resize.w, event.resize.h, 0, SDL_RESIZABLE | SDL_SWSURFACE);
  232.                      rect.w=event.resize.w;
  233.                      rect.h=event.resize.h;
  234.                      if (paused)
  235.                      {
  236.                          resized=1;
  237.                      }
  238.                      break;
  239.                 case SDL_KEYDOWN:
  240.                      if (event.key.keysym.sym == SDLK_SPACE)
  241.                      {
  242.                          paused=!paused;
  243.                          break;
  244.                      }
  245.                      if (event.key.keysym.sym != SDLK_ESCAPE)
  246.                      {
  247.                                              goto release_all;
  248.                      }
  249.                 case SDL_QUIT:
  250.                      goto release_all;
  251.             }
  252.         }
  253.                 /*
  254.                 * If the buffer is half empty or there are no more bytes in it
  255.                 * then fill it.
  256.                 */
  257.                 if (mp4_ptr > mp4_buffer + BUFFER_SIZE/2)
  258.                 {
  259.             int already_in_buffer = (mp4_buffer + BUFFER_SIZE - mp4_ptr);
  260.                     /* Move data if needed */
  261.                     if (already_in_buffer > 0)
  262.                 memcpy(mp4_buffer, mp4_ptr, already_in_buffer);
  263.                     /* Update mp4_ptr */
  264.                     mp4_ptr = mp4_buffer;
  265.                     /* read new data */
  266.                     if(feof(in_file))
  267.                                         break;
  268.             useful_bytes += fread(mp4_buffer + already_in_buffer,
  269.                                                                      1, BUFFER_SIZE - already_in_buffer,
  270.                                                                        in_file);

  271.         }
  272.                 if ((!paused)||(resized))
  273.                 {
  274.                 if (((SDL_GetTicks()-lastftick)>fpsdelay)||(resized))
  275.                 {
  276.                     lastftick=SDL_GetTicks();
  277.                                 /* This loop is needed to handle VOL/NVOP reading */
  278.                                 do{
  279.                                     /* Decode frame */
  280.                             dectime = msecond();                       
  281.                             used_bytes = dec_main(mp4_ptr, out_buffer, useful_bytes, &xvid_dec_stats);
  282.                             dectime = msecond() - dectime;
  283.                                         if(xvid_dec_stats.type==XVID_TYPE_VOL
  284.                                             && (xvid_dec_stats.data.vol.width != XDIM
  285.                                          ||xvid_dec_stats.data.vol.height != YDIM))
  286.                                      {
  287.                                                  //reallocate bigger out frame
  288.                                                 free(out_buffer);
  289.                                                 XDIM = xvid_dec_stats.data.vol.width;
  290.                                                  YDIM = xvid_dec_stats.data.vol.height;
  291.                                                  out_buffer = (unsigned char *) malloc(XDIM*YDIM*3/2);                                     
  292.                                                  if (!out_buffer)
  293.                                                  goto free_all_memory;
  294.                              
  295.                                                  //reallocate bigger yuv overlay
  296.                                       
  297.                                              SDL_FreeYUVOverlay(overlay);
  298.                                                 overlay = SDL_CreateYUVOverlay(XDIM, YDIM, SDL_YV12_OVERLAY, screen);
  299.                                                 if (!overlay)
  300.                                                 {
  301.                                        fprintf(stderr, "Couldn't create overlay: %s\n", SDL_GetError());
  302.                                            exit(4);
  303.                                 }                          
  304.                              
  305.                                           }                                    
  306.                                         /* Update buffer pointers */
  307.                                         if(used_bytes > 0) {
  308.                                             mp4_ptr += used_bytes;
  309.                                                 useful_bytes -= used_bytes;
  310.                                                 /* Total size */
  311.                                                 totalsize += used_bytes;
  312.                                         }
  313.                 }while (xvid_dec_stats.type <= 0 && useful_bytes > 0);
  314.                                 /* Check if there is a negative number of useful bytes left in buffer
  315.                                  * This means we went too far */
  316.                         if(useful_bytes < 0)
  317.                         break;
  318.                                 /* Updated data - Count only usefull decode time */
  319.                                 totaldectime += dectime;
  320.                         //display the decoded frame
  321.                         SDL_LockSurface(screen);
  322.                         SDL_LockYUVOverlay(overlay);
  323.                                 outy = out_buffer;
  324.                                 outu = out_buffer+XDIM*YDIM;
  325.                                 outv = out_buffer+XDIM*YDIM*5/4;
  326.                                 for(y=0;y<screen->h && y<overlay->h;y++)
  327.                                 {
  328.                                     op[0]=overlay->pixels[0]+overlay->pitches[0]*y;
  329.                                         op[1]=overlay->pixels[1]+overlay->pitches[1]*(y/2);
  330.                                         op[2]=overlay->pixels[2]+overlay->pitches[2]*(y/2);                       
  331.                                         memcpy(op[0],outy+y*XDIM,XDIM);
  332.                                         if(y%2 == 0)
  333.                                         {
  334.                                          memcpy(op[1],outu+XDIM/2*y/2,XDIM/2);
  335.                                                  memcpy(op[2],outv+XDIM/2*y/2,XDIM/2);          
  336.                                 }
  337.                                 }
  338.                         SDL_UnlockYUVOverlay(overlay);
  339.                         SDL_UnlockSurface(screen);        
  340.                         SDL_DisplayYUVOverlay(overlay, &rect);
  341.                                 /* Save output frame if required */
  342.                                 if (ARG_SAVEDECOUTPUT) {
  343.                                     sprintf(filename, "%sdec%05d", filepath, filenr);
  344.                                         if(write_image(filename, out_buffer)) {
  345.                                     fprintf(stderr,
  346.                                                 "Error writing decoded frame %s\n",
  347.                                                 filename);
  348.                                         }
  349.                 }
  350.                 filenr++;
  351.                 if (resized)
  352.                     resized = 0;
  353.              }
  354.           }
  355.           SDL_Delay(10);
  356.         } while (useful_bytes>0 || !feof(in_file));

  357.         useful_bytes = 0; /* Empty buffer */

  358. /*****************************************************************************
  359. *     Flush decoder buffers
  360. ****************************************************************************/

  361.         do {

  362.                 /* Fake vars */
  363.                 int used_bytes;
  364.                 double dectime;

  365.         do {
  366.                     dectime = msecond();
  367.                     used_bytes = dec_main(NULL, out_buffer, -1, &xvid_dec_stats);
  368.                     dectime = msecond() - dectime;
  369.         } while(used_bytes>=0 && xvid_dec_stats.type <= 0);

  370.         if (used_bytes < 0) {   /* XVID_ERR_END */
  371.             break;
  372.         }

  373.                 /* Updated data - Count only usefull decode time */
  374.                 totaldectime += dectime;

  375.                 /* Prints some decoding stats */
  376.                 if (!display_buffer_bytes) {
  377.                         printf("Frame %5d: type = %s, dectime(ms) =%6.1f, length(bytes) =%7d\n",
  378.                                         filenr, type2str(xvid_dec_stats.type), dectime, used_bytes);
  379.                 }

  380.                 /* Save output frame if required */
  381.                 if (ARG_SAVEDECOUTPUT) {
  382.                         sprintf(filename, "%sdec%05d", filepath, filenr);
  383.                         if(write_image(filename, out_buffer)) {
  384.                                 fprintf(stderr,
  385.                                                 "Error writing decoded frame %s\n",
  386.                                                 filename);
  387.                         }
  388.                 }

  389.                 filenr++;

  390.         }while(1);

  391. /*****************************************************************************
  392. *     Calculate totals and averages for output, print results
  393. ****************************************************************************/

  394.         if (filenr>0) {
  395.                 totalsize    /= filenr;
  396.                 totaldectime /= filenr;
  397.                 printf("Avg: dectime(ms) =%7.2f, fps =%7.2f, length(bytes) =%7d\n",
  398.                            totaldectime, 1000/totaldectime, (int)totalsize);
  399.         }else{
  400.                 printf("Nothing was decoded!\n");
  401.         }
  402.                
  403. /*****************************************************************************
  404. *      XviD PART  Stop
  405. ****************************************************************************/

  406. release_all:
  407.     SDL_FreeYUVOverlay(overlay);         
  408.           if (dec_handle) {
  409.                   status = dec_stop();
  410.                 if (status)   
  411.                         fprintf(stderr, "decore RELEASE problem return value %d\n", status);
  412.         }

  413. free_all_memory:
  414.     free(out_buffer);
  415.         free(mp4_buffer);
  416.         return 0;
  417. }




  418. /*****************************************************************************
  419. *               Usage function
  420. ****************************************************************************/

  421. static void usage()
  422. {

  423.         fprintf(stderr, "Usage : xvid_decraw [OPTIONS]\n");
  424.         fprintf(stderr, "Options :\n");
  425.         fprintf(stderr, " -asm           : use assembly optimizations (default=disabled)\n");
  426.         fprintf(stderr, " -i string      : input filename (default=stdin)\n");
  427.         fprintf(stderr, " -d             : save decoder output\n");
  428.         fprintf(stderr, " -f format      : choose output file format (tga, pnm, pgm)\n");
  429.         fprintf(stderr, " -w width       : init window width\n");
  430.         fprintf(stderr, " -h height      : init window height\n");
  431.         fprintf(stderr, " -help          : This help message\n");
  432.         fprintf(stderr, " (* means default)\n");

  433. }

  434. /* return the current time in milli seconds */
  435. static double
  436. msecond()
  437. {       
  438.         clock_t clk;
  439.         clk = clock();
  440.         return(clk * 1000 / CLOCKS_PER_SEC);
  441. }

  442.         
  443. static int write_image(char *prefix, unsigned char *image)
  444. {
  445.         char filename[1024];
  446.         char *ext;
  447.         int ret;

  448.         if (FORMAT == USE_PNM && BPP == 1) {
  449.                 ext = "pgm";
  450.         } else if (FORMAT == USE_PNM && BPP == 3) {
  451.                 ext = "pnm";
  452.         } else if (FORMAT == USE_TGA) {
  453.                 ext = "tga";
  454.         } else {
  455.                 fprintf(stderr, "Bug: should not reach this path code -- please report to xvid-devel@xvid.org with command line options used");
  456.                 exit(-1);
  457.         }

  458.         sprintf(filename, "%s.%s", prefix, ext);

  459.         if (FORMAT == USE_PNM) {
  460.                 ret = write_pnm(filename, image);
  461.         } else {
  462.                 ret = write_tga(filename, image);
  463.         }

  464.         return(ret);
  465. }

  466. static int write_tga(char *filename, unsigned char *image)
  467. {
  468.         FILE * f;
  469.         char hdr[18];

  470.         f = fopen(filename, "wb");
  471.         if ( f == NULL) {
  472.                 return -1;
  473.         }

  474.         hdr[0]  = 0; /* ID length */
  475.         hdr[1]  = 0; /* Color map type */
  476.         hdr[2]  = (BPP>1)?2:3; /* Uncompressed true color (2) or greymap (3) */
  477.         hdr[3]  = 0; /* Color map specification (not used) */
  478.         hdr[4]  = 0; /* Color map specification (not used) */
  479.         hdr[5]  = 0; /* Color map specification (not used) */
  480.         hdr[6]  = 0; /* Color map specification (not used) */
  481.         hdr[7]  = 0; /* Color map specification (not used) */
  482.         hdr[8]  = 0; /* LSB X origin */
  483.         hdr[9]  = 0; /* MSB X origin */
  484.         hdr[10] = 0; /* LSB Y origin */
  485.         hdr[11] = 0; /* MSB Y origin */
  486.         hdr[12] = (XDIM>>0)&0xff; /* LSB Width */
  487.         hdr[13] = (XDIM>>8)&0xff; /* MSB Width */
  488.         if (BPP > 1) {
  489.                 hdr[14] = (YDIM>>0)&0xff; /* LSB Height */
  490.                 hdr[15] = (YDIM>>8)&0xff; /* MSB Height */
  491.         } else {
  492.                 hdr[14] = ((YDIM*3)>>1)&0xff; /* LSB Height */
  493.                 hdr[15] = ((YDIM*3)>>9)&0xff; /* MSB Height */
  494.         }
  495.         hdr[16] = BPP*8;
  496.         hdr[17] = 0x00 | (1<<5) /* Up to down */ | (0<<4); /* Image descriptor */
  497.        
  498.         /* Write header */
  499.         fwrite(hdr, 1, sizeof(hdr), f);

  500.         /* write first plane */
  501.         fwrite(image, 1, XDIM*YDIM*BPP, f);

  502.         /* Write Y and V planes for YUV formats */
  503.         if (BPP == 1) {
  504.                 int i;

  505.                 /* Write the two chrominance planes */
  506.                 for (i=0; i<YDIM/2; i++) {
  507.                         fwrite(image+XDIM*YDIM + i*XDIM/2, 1, XDIM/2, f);
  508.                         fwrite(image+5*XDIM*YDIM/4 + i*XDIM/2, 1, XDIM/2, f);
  509.                 }
  510.         }


  511.         /* Close the file */
  512.         fclose(f);

  513.         return(0);
  514. }

  515. static int write_pnm(char *filename, unsigned char *image)
  516. {
  517.         FILE * f;

  518.         f = fopen(filename, "wb");
  519.         if ( f == NULL) {
  520.                 return -1;
  521.         }

  522.         if (BPP == 1) {
  523.                 int i;
  524.                 fprintf(f, "P5\n#xvid\n%i %i\n255\n", XDIM, YDIM*3/2);

  525.                 fwrite(image, 1, XDIM*YDIM, f);

  526.                 for (i=0; i<YDIM/2;i++) {
  527.                         fwrite(image+XDIM*YDIM + i*XDIM/2, 1, XDIM/2, f);
  528.                         fwrite(image+5*XDIM*YDIM/4 + i*XDIM/2, 1, XDIM/2, f);
  529.                 }
  530.         } else if (BPP == 3) {
  531.                 int i;
  532.                 fprintf(f, "P6\n#xvid\n%i %i\n255\n", XDIM, YDIM);
  533.                 for (i=0; i<XDIM*YDIM*3; i+=3) {
  534.                         fputc(image[i+2], f);
  535.                         fputc(image[i+1], f);
  536.                         fputc(image[i+0], f);
  537.                 }
  538.         }

  539.         fclose(f);

  540.         return 0;
  541. }

  542. /*****************************************************************************
  543. * Routines for decoding: init decoder, use, and stop decoder
  544. ****************************************************************************/

  545. /* init decoder before first run */
  546. static int
  547. dec_init(int use_assembler, int debug_level)
  548. {
  549.         int ret;

  550.         xvid_gbl_init_t   xvid_gbl_init;
  551.         xvid_dec_create_t xvid_dec_create;

  552.         /* Reset the structure with zeros */
  553.         memset(&xvid_gbl_init, 0, sizeof(xvid_gbl_init_t));
  554.         memset(&xvid_dec_create, 0, sizeof(xvid_dec_create_t));

  555.         /*------------------------------------------------------------------------
  556.          * XviD core initialization
  557.          *----------------------------------------------------------------------*/

  558.         /* Version */
  559.         xvid_gbl_init.version = XVID_VERSION;

  560.         /* Assembly setting */
  561.         if(use_assembler)
  562.             xvid_gbl_init.cpu_flags = 0;
  563.         else
  564.                 xvid_gbl_init.cpu_flags = XVID_CPU_FORCE;

  565.         xvid_gbl_init.debug = debug_level;

  566.         xvid_global(NULL, 0, &xvid_gbl_init, NULL);

  567.         /*------------------------------------------------------------------------
  568.          * XviD encoder initialization
  569.          *----------------------------------------------------------------------*/

  570.         /* Version */
  571.         xvid_dec_create.version = XVID_VERSION;

  572.         /*
  573.          * Image dimensions -- set to 0, xvidcore will resize when ever it is
  574.          * needed
  575.          */
  576.         xvid_dec_create.width = 0;
  577.         xvid_dec_create.height = 0;

  578.         ret = xvid_decore(NULL, XVID_DEC_CREATE, &xvid_dec_create, NULL);

  579.         dec_handle = xvid_dec_create.handle;

  580.         return(ret);
  581. }

  582. /* decode one frame  */
  583. static int
  584. dec_main(unsigned char *istream,
  585.                  unsigned char *ostream,
  586.                  int istream_size,
  587.                  xvid_dec_stats_t *xvid_dec_stats)
  588. {

  589.         int ret;

  590.         xvid_dec_frame_t xvid_dec_frame;

  591.         /* Reset all structures */
  592.         memset(&xvid_dec_frame, 0, sizeof(xvid_dec_frame_t));
  593.         memset(xvid_dec_stats, 0, sizeof(xvid_dec_stats_t));

  594.         /* Set version */
  595.         xvid_dec_frame.version = XVID_VERSION;
  596.         xvid_dec_stats->version = XVID_VERSION;

  597.         /* No general flags to set */
  598.         xvid_dec_frame.general          = 0;

  599.         /* Input stream */
  600.         xvid_dec_frame.bitstream        = istream;
  601.         xvid_dec_frame.length           = istream_size;

  602.         /* Output frame structure */
  603.         xvid_dec_frame.output.plane[0]  = ostream;
  604.         xvid_dec_frame.output.stride[0] = XDIM*BPP;
  605.         xvid_dec_frame.output.csp = CSP;

  606.         ret = xvid_decore(dec_handle, XVID_DEC_DECODE, &xvid_dec_frame, xvid_dec_stats);

  607.         return(ret);
  608. }

  609. /* close decoder to release resources */
  610. static int
  611. dec_stop()
  612. {
  613.         int ret;

  614.         ret = xvid_decore(dec_handle, XVID_DEC_DESTROY, NULL, NULL);

  615.         return(ret);
  616. }                   


复制代码
回复 支持 反对

使用道具 举报

发表于 2005-4-11 21:19:07 | 显示全部楼层
好东西,谢谢~!
回复 支持 反对

使用道具 举报

发表于 2005-4-12 22:37:44 | 显示全部楼层
不错,加精!
回复 支持 反对

使用道具 举报

发表于 2006-3-7 23:33:17 | 显示全部楼层
楼主请问怎样编译?
回复 支持 反对

使用道具 举报

发表于 2006-3-8 09:58:39 | 显示全部楼层
非常不错, 有空看看
回复 支持 反对

使用道具 举报

发表于 2006-3-8 17:43:40 | 显示全部楼层
楼主能做一个包吗?
方便大家下载与编译。

其需要xvid与SDL开发库?
回复 支持 反对

使用道具 举报

 楼主| 发表于 2006-3-9 09:10:36 | 显示全部楼层
Post by MatthewGong
楼主能做一个包吗?
方便大家下载与编译。

其需要xvid与SDL开发库?

没错,需要XVID与SDL开发库包。
回复 支持 反对

使用道具 举报

发表于 2006-3-9 11:28:13 | 显示全部楼层
xvid可以解压什么样的格式?和ffmpeg的关系?

# file bbb.m4v
bbb.m4v: MPEG sequence, v4, video, simple @ L1
# file aaa.mpeg
aaa.mpeg: MPEG sequence, v1, system multiplex
同样内容的两文件,结果
#ls -l bbb.m4v aaa.mpeg
-rw-r--r--  1 root root 408K 2006-03-04 15:12 aaa.mpeg
-rw-r--r--  1 root root 419K 2006-03-09 11:49 bbb.m4v
用m4v格式大小反而变大了?
回复 支持 反对

使用道具 举报

发表于 2006-3-9 12:12:10 | 显示全部楼层
楼主的播放器代码是在xvid源码包中的xvid_decraw.c代码基础上加SDL显示得到的?
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

快速回复 返回顶部 返回列表