📄 recmpeg.c
字号:
/* * recmpeg.c * * Copyright (C) Vivien Chappelier - 2001 * * This file is part of recmpeg, a free MPEG encoder based on libfame. * * recmpeg is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * recmpeg is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Make; see the file COPYING. If not, write to * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. * */#include <stdio.h>#include <unistd.h>#include <fcntl.h>#include <string.h>#include <fame.h>#ifdef HAS_GETOPT_H#include <getopt.h>#endif#ifndef WIN32#define O_BINARY 0#endif#define DEFAULT_BUFFER_SIZE 1024*1024#define CHUNK_SIZE 2048#ifdef USE_UDP#include <netinet/in.h>#include <netdb.h>#include <sys/socket.h>#include <arpa/inet.h>int is_address_multicast(unsigned long address){ if((address & 255) >= 224 && (address & 255) <= 239) return(1); return(0);}/* * open UDP socket */int udp_open(char * address, int port){ int enable = 1L; struct sockaddr_in stAddr; struct sockaddr_in stLclAddr; struct hostent * host; int sock; stAddr.sin_family = AF_INET; stAddr.sin_port = htons(port); if((host = gethostbyname(address)) == NULL) return(0); stAddr.sin_addr = *((struct in_addr *) host->h_addr_list[0]); /* Create a UDP socket */ if((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) return(0); /* Allow multiple instance of the client to share the same address and port */ if(setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *) &enable, sizeof(unsigned long int)) < 0) return(0);#ifdef USE_MULTICAST /* If the address is multicast, register to the multicast group */ if(is_address_multicast(stAddr.sin_addr.s_addr)) { struct ip_mreq stMreq; /* Bind the socket to port */ stLclAddr.sin_family = AF_INET; stLclAddr.sin_addr.s_addr = htonl(INADDR_ANY); stLclAddr.sin_port = stAddr.sin_port; if(bind(sock, (struct sockaddr*) & stLclAddr, sizeof(stLclAddr)) < 0) return(0); /* Register to a multicast address */ stMreq.imr_multiaddr.s_addr = stAddr.sin_addr.s_addr; stMreq.imr_interface.s_addr = INADDR_ANY; if(setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *) & stMreq, sizeof(stMreq)) < 0) return(0); } else#endif { /* Bind the socket to port */ stLclAddr.sin_family = AF_INET; stLclAddr.sin_addr.s_addr = htonl(INADDR_ANY); stLclAddr.sin_port = htons(0); if(bind(sock, (struct sockaddr*) & stLclAddr, sizeof(stLclAddr)) < 0) return(0); } connect(sock, (struct sockaddr*) & stAddr, sizeof(stAddr)); return(sock);}#endif/* * write to output by packets of CHUNK_SIZE length */int split_write(int fd, unsigned char *buffer, unsigned int size){ fd_set set; int r, w; w = 0; while(size > CHUNK_SIZE) { r = write(fd, buffer, CHUNK_SIZE); if(r < 0) return(r); w += r; size -= CHUNK_SIZE; buffer += CHUNK_SIZE; FD_ZERO(&set); FD_SET(fd, &set); if(select(fd+1, NULL, &set, NULL, NULL) <= 0) break; } r = write(fd, buffer, size); if(r < 0) return(r); w += r; return(w);}/* * parse command line */int parse(int argc, char *argv[], fame_context_t *fc, fame_parameters_t *p, int *number, int *buffer_size, int *ofile, int *ifile, int *sfile){ int index = -1; int c; /* options */#ifdef _GNU_SOURCE const struct option longopts[]={ {"number",1,0,'n'}, /* number of pictures to code: number or 0 (all) */ {"picture",1,0,'p'}, /* picture size: widthxheight or CIF,SIF,QCIF */ {"coding",1,0,'c'}, /* coding sequence: for example "IBBPBBPBB" */ {"quality",1,0,'q'}, /* quality: percentage of video quality */ {"bitrate",1,0,'b'}, /* bitrate: in bits/s, K for kilo, M for mega */ {"buffer",1,0,'B'}, /* buffer size: in bytes, K for kilo, M for mega */ {"alpha",1,0,'a'}, /* shape quality: percentage of shape accuracy */ {"search",1,0,'s'}, /* search range: motion estimation range */ {"slices",1,0,'S'}, /* slices: number of slices per frame */ {"fps",1,0,'f'}, /* framerate: fractional number of frames/sec */ {"refresh",1,0,'r'}, /* refresh: number of frames before a new sequence */ {"options",1,0,'o'}, /* options: intra_only, lossless_shape */ {"profile",1,0,'P'}, /* profile: name of the profile to use */ {"motion",1,0,'M'}, /* motion: motion estimation algorithm */ {"verbose",0,0,'v'}, /* verbose: when set, print messages */ {"help",0,0,'h'}, /* help: display help message */ {0,0,0,0} };#endif const char * shortopts = "n:p:c:q:b:B:a:s:S:f:r:o:P:M:vh";#ifdef _GNU_SOURCE while((c = getopt_long(argc,argv,shortopts,longopts,&index)) != -1)#else while((c = getopt(argc,argv,shortopts)) != -1)#endif { switch(c) { case 'n': *number = atoi(optarg); break; case 'p': /* picture size: widthxheight or CIF,SIF,QCIF,QSIF */ if(!strcmp("CIF", optarg)) { p->width = 352; p->height = 288; } else if(!strcmp("SIF", optarg)) { p->width = 352; p->height = 240; } else if(!strcmp("QCIF", optarg)) { p->width = 176; p->height = 144; } else if(strchr(optarg, 'x')) { p->width = atoi(optarg); p->height = atoi(strchr(optarg, 'x')+1); } else { return(index); } break; /* coding sequence: for example "IBBPBBPBB" */ case 'c': p->coding = optarg; break; /* quality percentage */ case 'q': p->quality = atoi(optarg); break; /* bitrate: in bits/s, K for kilo, M for mega */ case 'b': p->bitrate = atoi(optarg); if(optarg[strlen(optarg)-1] == 'K' || optarg[strlen(optarg)-1] == 'k') p->bitrate *= 1024; if(optarg[strlen(optarg)-1] == 'M' || optarg[strlen(optarg)-1] == 'm') p->bitrate *= 1024*1024; break; /* buffer size: in bytes, K for kilo, M for mega */ case 'B': *buffer_size = atoi(optarg); if(optarg[strlen(optarg)-1] == 'K' || optarg[strlen(optarg)-1] == 'k') *buffer_size *= 1024; if(optarg[strlen(optarg)-1] == 'M' || optarg[strlen(optarg)-1] == 'm') *buffer_size *= 1024*1024; break; /* shape quality percentage */ case 'a': p->shape_quality = atoi(optarg); break; /* search range: motion estimation range */ case 's': p->search_range = atoi(optarg); break; /* slices: number of slices per frame */ case 'S': p->slices_per_frame = atoi(optarg); break; /* framerate: fractional number of frames/sec */ case 'f': p->frame_rate_num = atoi(optarg); if(strchr(optarg, '/') != NULL) p->frame_rate_den = atoi(strchr(optarg, '/') + 1); else p->frame_rate_den = 1; break; /* refresh: number of frames before a new sequence */ case 'r': p->frames_per_sequence = atoi(optarg); break; /* motion: motion estimation algorithm */ case 'M': { fame_object_t *object; object = NULL; if(!strcmp(optarg, "none") || !strcmp(optarg, "NONE")) object = fame_get_object(fc, "motion/none"); if(!strcmp(optarg, "pmvfast") || !strcmp(optarg, "PMVFAST")) object = fame_get_object(fc, "motion/pmvfast"); if(!strcmp(optarg, "fourstep") || !strcmp(optarg, "FOURSTEP")) object = fame_get_object(fc, "motion/fourstep"); if(object) fame_register(fc, "motion", object); else fprintf(stderr, "unknown motion estimation algorithm %s\n", optarg); } break; /* profile: name of the default profile to use */ case 'P': { fame_object_t *object; object = NULL; if(!strcmp(optarg, "stats") || !strcmp(optarg, "STATS")) object = fame_get_object(fc, "profile/stats"); if(!strcmp(optarg, "mpeg1") || !strcmp(optarg, "MPEG1")) object = fame_get_object(fc, "profile/mpeg1"); if(!strcmp(optarg, "mpeg4") || !strcmp(optarg, "MPEG4")) object = fame_get_object(fc, "profile/mpeg4"); if(!strcmp(optarg, "mpeg4_simple") || !strcmp(optarg, "MPEG4_SIMPLE")) object = fame_get_object(fc, "profile/mpeg4/simple"); if(!strcmp(optarg, "mpeg4_shape") || !strcmp(optarg, "MPEG4_SHAPE")) object = fame_get_object(fc, "profile/mpeg4/shape"); if(object) fame_register(fc, "profile", object); else fprintf(stderr, "unknown profile %s\n", optarg); } break; /* verbose: when set, print messages */ case 'v': p->verbose = 1; break; /* help */ case 'h': return(-1); break; default: return(index); } } /* output file */ if(argc >= optind+1) {#ifdef USE_UDP if(!strncmp(argv[optind+0], "udp://", strlen("udp://"))) { char * host; int port; int sock; port = 10000; /* default port */ host = argv[optind+0] + strlen("udp://"); if(strchr(host, ':') != NULL) { /* port is specified */ port = atoi(strchr(host, ':') + 1); *strchr(host, ':') = 0; } /* open udp socket */ *ofile = udp_open(host, port); } else#endif { *ofile = open(argv[optind+0], O_BINARY | O_WRONLY | O_CREAT | O_TRUNC, 0666); } if(*ofile < 0) { char error[256]; sprintf(error, "Error opening %s for writing", argv[optind+0]); perror(error); exit(1); } } /* input file */ if(argc >= optind+2) { *ifile = open(argv[optind+1], O_BINARY | O_RDONLY); if(*ifile < 0) { char error[256]; sprintf(error, "Error opening %s for reading", argv[optind+1]); perror(error); exit(1); } } /* shape file */ if(argc >= optind+3) { *sfile = open(argv[optind+2], O_BINARY | O_RDONLY); if(*sfile < 0) { char error[256]; sprintf(error, "Error opening %s for reading", argv[optind+2]); perror(error); exit(1); } } return(0);}void usage(char const *name){ fprintf(stderr, "usage: %s options [output [input [mask]]]\n", name); fprintf(stderr, "options are\n"); fprintf(stderr, "\t%s\t%s\n", "-n --number", "number of pictures to code: number or 0 (all)"); fprintf(stderr, "\t%s\t%s\n", "-p --picture", "picture size: widthxheight or CIF,SIF,QCIF"); fprintf(stderr, "\t%s\t%s\n", "-c --coding", "coding sequence: for example \"IBBPBBPBB\""); fprintf(stderr, "\t%s\t%s\n", "-q --quality", "quality: percentage of video quality"); fprintf(stderr, "\t%s\t%s\n", "-b --bitrate", "bitrate: in bits/s, K for kilo, M for mega"); fprintf(stderr, "\t%s\t%s\n", "-B --buffer", "buffer size: in bytes, K for kilo, M for mega"); fprintf(stderr, "\t%s\t%s\n", "-a --alpha", "shape quality: percentage of shape accuracy"); fprintf(stderr, "\t%s\t%s\n", "-s --search", "search range: motion estimation range"); fprintf(stderr, "\t%s\t%s\n", "-S --slices", "slices: number of slices per frame"); fprintf(stderr, "\t%s\t%s\n", "-f --fps", "framerate: fractional number of frames/sec"); fprintf(stderr, "\t%s\t%s\n", "-r --refresh", "number of frames before a new sequence"); fprintf(stderr, "\t%s\t%s\n", "-P --profile", "profile: name of the profile to use"); fprintf(stderr, "\t%s\t%s\n", "-M --motion", "motion: motion estimation algorithm"); fprintf(stderr, "\t%s\t%s\n", "-v --verbose", "verbose: when set, print messages"); fprintf(stderr, "\t%s\t%s\n", "-h --help", "display this message"); exit(1);}int main(int argc, char *argv[]){ fame_parameters_t fp = FAME_PARAMETERS_INITIALIZER; fame_context_t *fc; fame_yuv_t yuv; unsigned char *buffer; unsigned char *shape; int width, height; int length, size; int ifile, ofile, sfile; FILE *bifile, *bsfile; int frame = 0; int number = 0; fc = fame_open(); /* default to CIF */ fp.width = 352; fp.height = 288; /* default files */ ifile = 0; ofile = 1; sfile = 0; /* default buffer size */ size = DEFAULT_BUFFER_SIZE; /* turn off verbose mode */ fp.verbose = 0; /* parse command line */ if(parse(argc, argv, fc, &fp, &number, &size, &ofile, &ifile, &sfile)) usage(argv[0]); yuv.w = fp.width; yuv.h = fp.height; yuv.p = fp.width; yuv.y = (unsigned char *) malloc(fp.width*fp.height*12/8); yuv.u = yuv.y + fp.width*fp.height; yuv.v = yuv.u + fp.width*fp.height/4; shape = (unsigned char *) malloc(fp.width*fp.height); buffer = (unsigned char *) malloc(size); fame_init(fc, &fp, buffer, size); /* buffered input (thx Eric Maffre) */ bifile = fdopen(ifile, "r"); if(sfile) bsfile = fdopen(sfile, "r"); do { if(fread(yuv.y, fp.width*fp.height, 1, bifile) <= 0) break; if(fread(yuv.u, fp.width*fp.height/4, 1, bifile) <= 0) break; if(fread(yuv.v, fp.width*fp.height/4, 1, bifile) <= 0) break; if(sfile) { if(fread(shape, fp.width*fp.height, 1, bsfile) <= 0) break; fame_start_frame(fc, &yuv, shape); } else fame_start_frame(fc, &yuv, NULL); /* TODO: would buffered output help? */ while(length = fame_encode_slice(fc)) { // TEMP // printf("%d\n", length*8); split_write(ofile, buffer, length); } fame_end_frame(fc, NULL); frame++; } while(!number || frame < number); length = fame_close(fc); split_write(ofile, buffer, length); free(yuv.y); free(buffer); fclose(bifile); if(sfile) fclose(bsfile); if(ifile != 0) close(ifile); if(ofile != 1) close(ofile); if(sfile != 0) close(sfile); fprintf(stderr, "encoded %d frames\n", frame); return(0);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -