📄 mpeg2enc.cc
字号:
/* mpeg2enc.cc, YUV4MPEG / mjpegtools command line wrapper for * mpeg2enc++ library *//* Copyright (C) 1996, MPEG Software Simulation Group. All Rights Reserved. *//* * Disclaimer of Warranty * * These software programs are available to the user without any license fee or * royalty on an "as is" basis. The MPEG Software Simulation Group disclaims * any and all warranties, whether express, implied, or statuary, including any * implied warranties or merchantability or of fitness for a particular * purpose. In no event shall the copyright-holder be liable for any * incidental, punitive, or consequential damages of any kind whatsoever * arising from the use of these programs. * * This disclaimer of warranty extends to the user of these programs and user's * customers, employees, agents, transferees, successors, and assigns. * * The MPEG Software Simulation Group does not represent or warrant that the * programs furnished hereunder are free of infringement of any third-party * patents. * * Commercial implementations of MPEG-1 and MPEG-2 video, including shareware, * are subject to royalty fees to patent holders. Many of these patents are * general enough such that they are unavoidable regardless of implementation * design. * *//* Modifications and enhancements (C) 2000/2001 Andrew Stevens *//* These modifications are 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 of * the License, or (at your option) any later version. * * This program 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 this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. * */#include <config.h>#include <stdio.h>#ifdef HAVE_GETOPT_H#include <getopt.h>#endif#include <string.h>#include <stdio.h>#include <stdlib.h>#include <fcntl.h>#include "mpeg2encoder.hh"#include "mpeg2encoptions.hh"#include "encoderparams.hh"#include "picturereader.hh"#include "elemstrmwriter.hh"#include "quantize.hh"#include "ratectl.hh"#include "seqencoder.hh"#include "mpeg2coder.hh"#include "format_codes.h"#include "mpegconsts.h"#ifdef HAVE_ALTIVEC/* needed for ALTIVEC_BENCHMARK and print_benchmark_statistics() */#include "../utils/altivec/altivec_conf.h"#endif/************************** * * Derived class for File (actually: pipe and FIFO) based bitstream output * *************************/class FILE_StrmWriter : public ElemStrmWriter{public: FILE_StrmWriter( EncoderParams &encparams, const char *outfilename ) { /* open output file */ if (!(outfile=fopen(outfilename,"wb"))) { mjpeg_error_exit1("Couldn't create output file %s",outfilename); } } virtual void WriteOutBufferUpto( const uint8_t *buffer, const uint32_t flush_upto ) { size_t written = fwrite( buffer, sizeof(uint8_t), static_cast<size_t>(flush_upto), outfile ); if( written != static_cast<size_t>(flush_upto) ) { mjpeg_error_exit1( strerror(ferror(outfile)) ); } flushed += flush_upto; } virtual ~FILE_StrmWriter() { fclose( outfile ); } virtual size_t BitCount() { return flushed * 8LL; }private: FILE *outfile;};/************************** * * Derived class for File (actually: pipe and FIFO) based input of frames * in the YUV4MPEG2 format * *************************/class Y4MPipeReader : public PictureReader{public: Y4MPipeReader( EncoderParams &encparams, int istrm_fd ); ~Y4MPipeReader(); void StreamPictureParams( MPEG2EncInVidParams &strm );protected: bool LoadFrame( );private: int PipeRead( uint8_t *buf, int len); int pipe_fd; y4m_stream_info_t _si; y4m_frame_info_t _fi;}; Y4MPipeReader::Y4MPipeReader( EncoderParams &encparams, int istrm_fd ) : PictureReader( encparams ), pipe_fd( istrm_fd ){ y4m_init_stream_info(&_si); y4m_init_frame_info(&_fi);}Y4MPipeReader::~Y4MPipeReader(){ y4m_fini_stream_info(&_si); y4m_fini_frame_info(&_fi);}/**************************************** * * Initialise the reader and return the parameter of the video stream * to be encoded. * * WARNING: This routine must run before encoder parameters are defined. * TODO: Reader should be constructed before EncoderParams and this * routine invoked from EncoderParams constructor... * *****************************************/void Y4MPipeReader::StreamPictureParams( MPEG2EncInVidParams &strm ){ int n; y4m_ratio_t sar; if ((n = y4m_read_stream_header (pipe_fd, &_si)) != Y4M_OK) { mjpeg_log( LOG_ERROR, "Could not read YUV4MPEG2 header: %s!", y4m_strerr(n)); exit (1); } strm.horizontal_size = y4m_si_get_width(&_si); strm.vertical_size = y4m_si_get_height(&_si); strm.frame_rate_code = mpeg_framerate_code(y4m_si_get_framerate(&_si)); strm.interlacing_code = y4m_si_get_interlace(&_si); /* Deduce MPEG aspect ratio from stream's frame size and SAR... (always as an MPEG-2 code; that's what caller expects). */ sar = y4m_si_get_sampleaspect(&_si); strm.aspect_ratio_code = mpeg_guess_mpeg_aspect_code(2, sar, strm.horizontal_size, strm.vertical_size); if(strm.horizontal_size <= 0) { mjpeg_error_exit1("Horizontal size from input stream illegal"); } if(strm.vertical_size <= 0) { mjpeg_error("Vertical size from input stream illegal"); }}/***************************** * * LoadFrame - pull in the image data planes from pipe (planar YUV420) * * RETURN: true iff EOF or ERROR * ****************************/bool Y4MPipeReader::LoadFrame( ){ int h,v,y; int buffer_slot = frames_read % input_imgs_buf_size; if ((y = y4m_read_frame_header (pipe_fd, &_si, &_fi)) != Y4M_OK) { if( y != Y4M_ERR_EOF ) mjpeg_log (LOG_WARN, "Error reading frame header (%d): code%s!", frames_read, y4m_strerr (y)); return true; } v = encparams.vertical_size; h = encparams.horizontal_size; int i; for(i=0;i<v;i++) { if( PipeRead(input_imgs_buf[buffer_slot][0]+i*encparams.phy_width,h)!=h) return true; } lum_mean[buffer_slot] = LumMean(input_imgs_buf[buffer_slot][0] ); v = encparams.vertical_size/2; h = encparams.horizontal_size/2; for(i=0;i<v;i++) { if(PipeRead(input_imgs_buf[buffer_slot][1]+i*encparams.phy_chrom_width,h)!=h) return true; } for(i=0;i<v;i++) { if(PipeRead(input_imgs_buf[buffer_slot][2]+i*encparams.phy_chrom_width,h)!=h) return true; } return false;}int Y4MPipeReader::PipeRead(uint8_t *buf, int len){ int n, r; r = 0; while(r<len) { n = read(pipe_fd,buf+r,len-r); if(n==0) return r; r += n; } return r;}/************************** * * Derived class for options set from command line * *************************/class MPEG2EncCmdLineOptions : public MPEG2EncOptions{public: MPEG2EncCmdLineOptions(); int SetFromCmdLine(int argc, char *argv[] ); void Usage(); void StartupBanner(); void SetFormatPresets( const MPEG2EncInVidParams &strm );private: void DisplayFrameRates(); void DisplayAspectRatios(); int ParseCustomMatrixFile(const char *fname, int dbug); void ParseCustomOption(const char *arg);public: int istrm_fd; char *outfilename;};void MPEG2EncCmdLineOptions::SetFormatPresets( const MPEG2EncInVidParams &strm ){ if( MPEG2EncOptions::SetFormatPresets( strm ) ) Usage();}MPEG2EncCmdLineOptions::MPEG2EncCmdLineOptions() : MPEG2EncOptions(){ outfilename = 0; istrm_fd = 0; }void MPEG2EncCmdLineOptions::DisplayFrameRates(void){ unsigned int i; printf("Frame-rate codes:\n"); for( i = 1; mpeg_valid_framerate_code(i); ++i ) { printf( "%2d - %s\n", i, mpeg_framerate_code_definition(i)); } exit(0);}void MPEG2EncCmdLineOptions::DisplayAspectRatios(void){ unsigned int i; printf("\nDisplay aspect ratio codes:\n"); for( i = 1; mpeg_valid_aspect_code(2, i); ++i ) { printf( "%2d - %s\n", i, mpeg_aspect_code_definition(2,i)); } exit(0);}int MPEG2EncCmdLineOptions::ParseCustomMatrixFile(const char *fname, int dbug){ FILE *fp; uint16_t q[128]; int i, j, row; char line[80]; fp = fopen(fname, "r"); if (!fp) { mjpeg_error("can not open custom matrix file '%s'", fname); return(-1); } row = i = 0; while (fgets(line, sizeof(line), fp)) { row++; /* Empty lines (\n only) and comments are ignored */ if ((strlen(line) == 1) || line[0] == '#') continue; j = sscanf(line, "%hu,%hu,%hu,%hu,%hu,%hu,%hu,%hu\n", &q[i+0], &q[i+1], &q[i+2], &q[i+3], &q[i+4], &q[i+5], &q[i+6], &q[i+7]); if (j != 8) { mjpeg_error("line %d ('%s') of '%s' malformed", row, line, fname); break; } for (j = 0; j < 8; j++) { if (q[i + j] < 1 || q[i + j] > 255) { mjpeg_error("entry %d (%u) in line %d from '%s' invalid", j, q[i + j], row, fname); i = -1; break; } } i += 8; } fclose(fp); if (i != 128) { mjpeg_error("file '%s' did NOT have 128 values - ignoring custom matrix file", fname); return(-1); } for (j = 0; j < 64; j++) { custom_intra_quantizer_matrix[j] = q[j]; custom_nonintra_quantizer_matrix[j] = q[j + 64]; } if (dbug) { mjpeg_info("INTRA and NONINTRA tables from '%s'",fname); for (j = 0; j < 128; j += 8) { mjpeg_info("%u %u %u %u %u %u %u %u", q[j + 0], q[j + 1], q[j + 2], q[j + 3], q[j + 4], q[j + 5], q[j + 6], q[j + 7]); } } return(0);}void MPEG2EncCmdLineOptions::ParseCustomOption(const char *arg){ if (strcmp(arg, "kvcd") == 0) hf_quant = 3; else if (strcmp(arg, "hi-res") == 0) hf_quant = 2; else if (strcmp(arg, "default") == 0) { hf_quant = 0; hf_q_boost = 0; } else if (strcmp(arg, "tmpgenc") == 0) hf_quant = 4; else if (strncasecmp(arg, "file=", 5) == 0) { if (ParseCustomMatrixFile(arg + 5, arg[0] == 'F' ? 1 : 0) == 0) hf_quant = 5; } else if (strcmp(arg, "help") == 0) { fprintf(stderr, "Quantization matrix names:\n\n"); fprintf(stderr, "\thelp - this message\n"); fprintf(stderr, "\tkvcd - matrices from http://www.kvcd.net\n"); fprintf(stderr, "\thi-res - high resolution tables (same as -H)\n"); fprintf(stderr, "\tdefault - turn off -N or -H (use standard tables)\n"); fprintf(stderr, "\ttmpgenc - TMPGEnc tables (http://www.tmpgenc.com)\n"); fprintf(stderr, "\tfile=filename - filename contains custom matrices\n"); fprintf(stderr, "\t\t8 comma separated values per line. 8 lines per matrix, INTRA matrix first, then NONINTRA\n"); exit(0); } else mjpeg_error_exit1("Unknown type '%s' used with -K/--custom-quant", arg);}void MPEG2EncCmdLineOptions::Usage(){ fprintf(stderr,"--verbose|-v num\n" " Level of verbosity. 0 = quiet, 1 = normal 2 = verbose/debug\n""--format|-f fmt\n"" Set pre-defined mux format fmt.\n"" [0 = Generic MPEG1, 1 = standard VCD, 2 = user VCD,\n"" 3 = Generic MPEG2, 4 = standard SVCD, 5 = user SVCD,\n"" 6 = VCD Stills sequences, 7 = SVCD Stills sequences, 8|9 = DVD]\n""--aspect|-a num\n"" Set displayed image aspect ratio image (default: 2 = 4:3)\n"" [1 = 1:1, 2 = 4:3, 3 = 16:9, 4 = 2.21:1]\n""--frame-rate|-F num\n"" Set playback frame rate of encoded video\n"" (default: frame rate of input stream)\n"" 0 = Display frame rate code table\n""--video-bitrate|-b num\n"" Set Bitrate of compressed video in KBit/sec\n"" (default: 1152 for VCD, 2500 for SVCD, 7500 for DVD)\n""--nonvideo-bitrate|-B num\n"" Non-video data bitrate to assume for sequence splitting\n"" calculations (see also --sequence-length).\n""--quantisation|-q num\n"" Image data quantisation factor [1..31] (1 is best quality, no default)\n"" When quantisation is set variable bit-rate encoding is activated and\n"" the --bitrate value sets an *upper-bound* video data-rate\n""--output|-o pathname\n"" Pathname of output file or fifo (REQUIRED!!!)\n""--target-still-size|-T size\n"" Size in KB of VCD stills\n""--interlace-mode|-I num\n"" Sets MPEG 2 motion estimation and encoding modes:\n"" 0 = Progressive (non-interlaced)(Movies)\n"" 1 = Interlaced source material (video)\n"" 2 = Interlaced source material, per-field-encoding (video)\n""--motion-search-radius|-r num\n"" Motion compensation search radius [0..32] (default 16)\n""--reduction-4x4|-4 num\n"" Reduction factor for 4x4 subsampled candidate motion estimates\n"" [1..4] [1 = max quality, 4 = max. speed] (default: 2)\n""--reduction-2x2|-2 num\n"" Reduction factor for 2x2 subsampled candidate motion estimates\n"" [1..4] [1 = max quality, 4 = max. speed] (default: 3)\n""--min-gop-size|-g num\n"" Minimum size Group-of-Pictures (default depends on selected format)\n""--max-gop-size|-G num\n"" Maximum size Group-of-Pictures (default depends on selected format)\n"" If min-gop is less than max-gop, mpeg2enc attempts to place GOP\n"" boundaries to coincide with scene changes\n""--closed-gop|-c\n"" All Group-of-Pictures are closed. Useful for authoring multi-angle DVD\n""--force-b-b-p|-P\n"" Preserve two B frames between I/P frames when placing GOP boundaries\n""--quantisation-reduction|-Q num\n"" Max. quantisation reduction for highly active blocks\n"" [0.0 .. 4.0] (default: 0.0)\n""--quant-reduction-max-var|-X num\n"" Luma variance below which quantisation boost (-Q) is used\n"" [0.0 .. 2500.0](default: 0.0)\n""--video-buffer|-V num\n"" Target decoders video buffer size in KB (default 46)\n""--video-norm|-n n|p|s\n"" Tag output to suit playback in specified video norm\n"" (n = NTSC, p = PAL, s = SECAM) (default: PAL)\n""--sequence-length|-S num\n"" Place a sequence boundary in the video stream so they occur every\n"" num Mbytes once the video is multiplexed with audio etc.\n"" N.b. --non-video-bitrate is used to the bitrate of the other\n"" data that will be multiplexed with this video stream\n""--3-2-pulldown|-p\n"" Generate header flags for 3-2 pull down of 24fps movie material\n""--intra_dc_prec|-D [8..11]\n"" Set number of bits precision for DC (base colour) of blocks in MPEG-2\n""--reduce-hf|-N num\n"" [0.0..2.0] Reduce hf resolution (increase quantization) by num (default: 0.0)\n""--keep-hf|-H\n"" Maximise high-frequency resolution - useful for high quality sources\n"" and/or high bit-rates)\n""--sequence-header-every-gop|-s\n"" Include a sequence header every GOP if the selected format doesn't\n"" do so by default.\n""--no-dummy-svcd-SOF|-d\n"" Do not generate dummy SVCD scan-data for the ISO CD image\n"" generator \"vcdimager\" to fill in.\n""--playback-field-order|-z b|t\n"
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -