codec.c
上传用户:hjq518
上传日期:2021-12-09
资源大小:5084k
文件大小:14k
源码类别:

Audio

开发平台:

Visual C++

  1. /*****************************************************************************
  2.  * codec.c: vfw x264 encoder
  3.  *****************************************************************************
  4.  * Copyright (C) 2003 Laurent Aimar
  5.  * $Id: codec.c,v 1.1 2004/06/03 19:27:09 fenrir Exp $
  6.  *
  7.  * Authors: Justin Clay
  8.  *          Laurent Aimar <fenrir@via.ecp.fr>
  9.  *
  10.  * This program is free software; you can redistribute it and/or modify
  11.  * it under the terms of the GNU General Public License as published by
  12.  * the Free Software Foundation; either version 2 of the License, or
  13.  * (at your option) any later version.
  14.  *
  15.  * This program is distributed in the hope that it will be useful,
  16.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  18.  * GNU General Public License for more details.
  19.  *
  20.  * You should have received a copy of the GNU General Public License
  21.  * along with this program; if not, write to the Free Software
  22.  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
  23.  *****************************************************************************/
  24. #include "x264vfw.h"
  25. #include <stdio.h> /* debug only */
  26. #include <io.h>
  27. #define X264_MAX(a,b) ( (a)>(b) ? (a) : (b) )
  28. #define X264_MIN(a,b) ( (a)<(b) ? (a) : (b) )
  29. /* get_csp:
  30.  *  return a valid x264 CSP or X264_CSP_NULL if unsuported */
  31. static int get_csp( BITMAPINFOHEADER *hdr )
  32. {
  33.     switch( hdr->biCompression )
  34.     {
  35.         case FOURCC_I420:
  36.         case FOURCC_IYUV:
  37.             return X264_CSP_I420;
  38.         case FOURCC_YV12:
  39.             return X264_CSP_YV12;
  40.         case FOURCC_YUYV:
  41.         case FOURCC_YUY2:
  42.             return X264_CSP_YUYV;
  43.         case BI_RGB:
  44.         {
  45.             int i_vflip = hdr->biHeight < 0 ? 0 : X264_CSP_VFLIP;
  46.             if( hdr->biBitCount == 24 )
  47.                 return X264_CSP_BGR | i_vflip;
  48.             if( hdr->biBitCount == 32 )
  49.                 return X264_CSP_BGRA | i_vflip;
  50.             else
  51.                 return X264_CSP_NONE;
  52.         }
  53.         default:
  54.             return X264_CSP_NONE;
  55.     }
  56. }
  57. /* Test that we can do the compression */
  58. LRESULT compress_query( CODEC *codec, BITMAPINFO *lpbiInput, BITMAPINFO *lpbiOutput )
  59. {
  60.     BITMAPINFOHEADER *inhdr = &lpbiInput->bmiHeader;
  61.     BITMAPINFOHEADER *outhdr = &lpbiOutput->bmiHeader;
  62.     CONFIG           *config = &codec->config;
  63.     if( get_csp( inhdr ) == X264_CSP_NONE )
  64.         return ICERR_BADFORMAT;
  65.     if( lpbiOutput == NULL )
  66.         return ICERR_OK;
  67.     if( inhdr->biWidth != outhdr->biWidth ||
  68.         inhdr->biHeight != outhdr->biHeight )
  69.         return ICERR_BADFORMAT;
  70.     /* We need x16 width/height */
  71.     if( inhdr->biWidth % 16 != 0 || inhdr->biHeight % 16 != 0 )
  72.         return ICERR_BADFORMAT;
  73.     if( inhdr->biCompression != mmioFOURCC( config->fcc[0], config->fcc[1],
  74.                                             config->fcc[2], config->fcc[3] ) )
  75.         return ICERR_BADFORMAT;
  76.     return ICERR_OK;
  77. }
  78. /* */
  79. LRESULT compress_get_format( CODEC *codec, BITMAPINFO *lpbiInput, BITMAPINFO *lpbiOutput )
  80. {
  81.     BITMAPINFOHEADER *inhdr = &lpbiInput->bmiHeader;
  82.     BITMAPINFOHEADER *outhdr = &lpbiOutput->bmiHeader;
  83.     CONFIG           *config = &codec->config;
  84.     if( get_csp( inhdr ) == X264_CSP_NONE )
  85.         return ICERR_BADFORMAT;
  86.     if( lpbiOutput == NULL )
  87.         return sizeof(BITMAPINFOHEADER);
  88.     memcpy( outhdr, inhdr, sizeof( BITMAPINFOHEADER ) );
  89.     outhdr->biSize = sizeof( BITMAPINFOHEADER );
  90.     outhdr->biSizeImage = compress_get_size( codec, lpbiInput, lpbiOutput );
  91.     outhdr->biXPelsPerMeter = 0;
  92.     outhdr->biYPelsPerMeter = 0;
  93.     outhdr->biClrUsed = 0;
  94.     outhdr->biClrImportant = 0;
  95.     outhdr->biCompression = mmioFOURCC( config->fcc[0], config->fcc[1],
  96.                                         config->fcc[2], config->fcc[3] );
  97.     return ICERR_OK;
  98. }
  99. /* */
  100. LRESULT compress_get_size( CODEC *codec, BITMAPINFO *lpbiInput, BITMAPINFO *lpbiOutput )
  101. {
  102.     return 2 * lpbiOutput->bmiHeader.biWidth * lpbiOutput->bmiHeader.biHeight * 3;
  103. }
  104. /* */
  105. LRESULT compress_frames_info(CODEC * codec, ICCOMPRESSFRAMES * icf )
  106. {
  107.     codec->fincr = icf->dwScale;
  108.     codec->fbase = icf->dwRate;
  109.     codec->config.i_frame_total = icf->lFrameCount;
  110.     return ICERR_OK;
  111. }
  112. static void x264_log_vfw( void *p_private, int i_level, const char *psz_fmt, va_list arg )
  113. {
  114.     char error_msg[1024];
  115.     int idx;
  116.     HWND *hCons = p_private;
  117.     vsprintf( error_msg, psz_fmt, arg );
  118.     /* strip final linefeeds (required) */
  119.     idx=strlen( error_msg ) - 1;
  120.     while( idx >= 0 && error_msg[idx] == 'n' )
  121.         error_msg[idx--] = 0;
  122.     if(!( *hCons ) ) {
  123.         *hCons = CreateDialog( g_hInst, MAKEINTRESOURCE( IDD_ERRCONSOLE ), NULL,
  124.                  callback_err_console );
  125.         //ShowWindow( *hCons, SW_SHOW );
  126.     }
  127.     idx = SendDlgItemMessage( *hCons, IDC_CONSOLE, LB_ADDSTRING, 0, ( LPARAM )error_msg );
  128.     /* make sure that the last item added is visible (autoscroll) */
  129.     if( idx >= 0 )
  130.         SendDlgItemMessage( *hCons, IDC_CONSOLE, LB_SETTOPINDEX, ( WPARAM )idx, 0 );
  131. }
  132. static void statsfilename_renumber( char *dest, char *src, int i_pass )
  133. {
  134.     char *last_dot = strrchr( src, '.' );
  135.     char *last_slash = X264_MAX( strrchr( src, '/' ), strrchr( src, '\' ) );
  136.     char pass_str[5];
  137.     sprintf( pass_str, "-%i", i_pass );
  138.     strcpy( dest, src );
  139.     if( last_slash < last_dot ) {
  140.         dest[ last_dot - src ] = 0;
  141.         strcat( dest, pass_str );
  142.         strcat( dest, last_dot );
  143.     }
  144.     else
  145.     {
  146.         strcat( dest, pass_str );
  147.     }
  148. }
  149. /* */
  150. LRESULT compress_begin(CODEC * codec, BITMAPINFO * lpbiInput, BITMAPINFO * lpbiOutput )
  151. {
  152.     CONFIG *config = &codec->config;
  153.     x264_param_t param;
  154.     int pass_number;
  155.     /* Destroy previous handle */
  156.     if( codec->h != NULL )
  157.     {
  158.         x264_encoder_close( codec->h );
  159.         codec->h = NULL;
  160.     }
  161.     /* Get default param */
  162.     x264_param_default( &param );
  163.     param.rc.psz_stat_out = malloc (MAX_PATH);
  164.     param.rc.psz_stat_in = malloc (MAX_PATH);
  165.     param.i_threads = config->i_threads;
  166.     param.analyse.i_noise_reduction = config->i_noise_reduction;
  167.     param.i_log_level = config->i_log_level - 1;
  168.     param.pf_log = x264_log_vfw;
  169.     param.p_log_private = malloc( sizeof( HWND ) );
  170.     *( ( HWND * )param.p_log_private ) = NULL; /* error console window handle */
  171.     codec->hCons = ( HWND * )param.p_log_private;
  172.     param.analyse.b_psnr = 0;
  173.     /* Set params: TODO to complete */
  174.     param.i_width = lpbiInput->bmiHeader.biWidth;
  175.     param.i_height= lpbiInput->bmiHeader.biHeight;
  176.     param.i_fps_num = codec->fbase;
  177.     param.i_fps_den = codec->fincr;
  178.     param.i_frame_total = config->i_frame_total;
  179.     param.i_frame_reference = config->i_refmax;
  180.     param.i_keyint_min = config->i_keyint_min;
  181.     param.i_keyint_max = config->i_keyint_max;
  182.     param.i_scenecut_threshold = config->i_scenecut_threshold;
  183.     param.rc.i_qp_min = config->i_qp_min;
  184.     param.rc.i_qp_max = config->i_qp_max;
  185.     param.rc.i_qp_step = config->i_qp_step;
  186.     param.b_deblocking_filter = config->b_filter;
  187.     param.b_cabac = config->b_cabac;
  188.     if( config->b_cabac && config->i_trellis )
  189.         param.analyse.i_trellis = 1;
  190.     param.analyse.b_chroma_me = config->b_chroma_me;
  191.     param.rc.f_ip_factor = 1 + (float)config->i_key_boost / 100;
  192.     param.rc.f_pb_factor = 1 + (float)config->i_b_red / 100;
  193.     param.rc.f_qcompress = (float)config->i_curve_comp / 100;
  194.     param.vui.i_sar_width = config->i_sar_width;
  195.     param.vui.i_sar_height = config->i_sar_height;
  196.     param.i_bframe = config->i_bframe;
  197.     if( config->i_bframe > 1 && config->b_b_wpred)
  198.         param.analyse.b_weighted_bipred = 1;
  199.     if( config->i_bframe > 1 && config->b_b_refs)
  200.         param.b_bframe_pyramid = 1;
  201.     param.b_bframe_adaptive = config->b_bframe_adaptive;
  202.     param.analyse.b_bidir_me = config->b_bidir_me;
  203.     param.i_bframe_bias = config->i_bframe_bias;
  204.     param.analyse.i_subpel_refine = config->i_subpel_refine + 1; /* 0..5 -> 1..6 */
  205.     if (param.analyse.i_subpel_refine == 7)
  206.     {
  207.         param.analyse.i_subpel_refine = 6;
  208.         param.analyse.b_bframe_rdo = 1;
  209.     }
  210.     param.analyse.i_me_method = config->i_me_method;
  211.     param.analyse.i_me_range = config->i_me_range;
  212.     /* bframe prediction - gui goes alphabetically, so 1=SPATIAL, 2=TEMPORAL */
  213.     switch(config->i_direct_mv_pred) {
  214.         case 0: param.analyse.i_direct_mv_pred = X264_DIRECT_PRED_SPATIAL; break;
  215.         case 1: param.analyse.i_direct_mv_pred = X264_DIRECT_PRED_TEMPORAL; break;
  216.     }
  217.     param.i_deblocking_filter_alphac0 = config->i_inloop_a;
  218.     param.i_deblocking_filter_beta = config->i_inloop_b;
  219.     param.analyse.inter = 0;
  220.     if( config->b_bsub16x16 )
  221.         param.analyse.inter |= X264_ANALYSE_BSUB16x16;
  222.     if( config->b_psub16x16 )
  223.     {
  224.         param.analyse.inter |= X264_ANALYSE_PSUB16x16;
  225.         if( config->b_psub8x8 )
  226.             param.analyse.inter |= X264_ANALYSE_PSUB8x8;
  227.     }
  228.     if( config->b_i4x4 )
  229.         param.analyse.inter |= X264_ANALYSE_I4x4;
  230.     if( config->b_i8x8 )
  231.         param.analyse.inter |= X264_ANALYSE_I8x8;
  232.     param.analyse.b_transform_8x8 = config->b_dct8x8;
  233.     if( config->b_mixedref )
  234.         param.analyse.b_mixed_references = 1;
  235.     switch( config->i_encoding_type )
  236.     {
  237.         case 0: /* 1 PASS ABR */
  238.             param.rc.b_cbr = 1;
  239.             param.rc.i_bitrate = config->bitrate;
  240.             break;
  241.         case 1: /* 1 PASS CQ */
  242.             param.rc.i_qp_constant = config->i_qp;
  243.             break;
  244.         default:
  245.         case 2: /* 2 PASS */
  246.         {
  247.             for( pass_number = 1; pass_number < 99; pass_number++ )
  248.             {
  249.                 FILE *f;
  250.                 statsfilename_renumber( param.rc.psz_stat_out, config->stats, pass_number );
  251.                 if( ( f = fopen( param.rc.psz_stat_out, "r" ) ) != NULL )
  252.                 {
  253.                     fclose( f );
  254.                     if( config->i_pass == 1 )
  255.                         unlink( param.rc.psz_stat_out );
  256.                 }
  257.                 else break;
  258.             }
  259.             if( config->i_pass > pass_number )
  260.             {
  261.                 /* missing 1st pass statsfile */
  262.                 free( param.rc.psz_stat_out );
  263.                 free( param.rc.psz_stat_in );
  264.                 return ICERR_ERROR;
  265.             }
  266.             param.rc.i_bitrate = config->i_2passbitrate;
  267.             param.rc.b_cbr = 1;
  268.             if( config->i_pass == 1 )
  269.             {
  270.                 statsfilename_renumber( param.rc.psz_stat_out, config->stats, 1 );
  271.                 param.rc.b_stat_write = 1;
  272.                 param.rc.f_rate_tolerance = 4;
  273.                 if( config->b_fast1pass )
  274.                 {
  275.                     /* adjust or turn off some flags to gain speed, if needed */
  276.                     param.analyse.i_subpel_refine = X264_MAX( X264_MIN( 3, param.analyse.i_subpel_refine - 1 ), 1 );
  277.                     param.i_frame_reference = ( param.i_frame_reference + 1 ) >> 1;
  278.                     param.analyse.inter &= ( ~X264_ANALYSE_PSUB8x8 );
  279.                     param.analyse.inter &= ( ~X264_ANALYSE_BSUB16x16 );
  280.                 }
  281.             }
  282.             else
  283.             {
  284.                 statsfilename_renumber( param.rc.psz_stat_in, config->stats, pass_number - 1 );
  285.                 param.rc.b_stat_read = 1;
  286.                 if( config->b_updatestats )
  287.                     param.rc.b_stat_write = 1;
  288.                 param.rc.f_rate_tolerance = 1;
  289.             }
  290.             break;
  291.         }
  292.     }
  293.     /* Open the encoder */
  294.     codec->h = x264_encoder_open( &param );
  295.     free( param.rc.psz_stat_out );
  296.     free( param.rc.psz_stat_in );
  297.     if( codec->h == NULL )
  298.         return ICERR_ERROR;
  299.     return ICERR_OK;
  300. }
  301. /* */
  302. LRESULT compress_end(CODEC * codec)
  303. {
  304.     if( codec->h != NULL )
  305.     {
  306.         x264_encoder_close( codec->h );
  307.         codec->h = NULL;
  308.     }
  309.     free( codec->hCons );
  310.     codec->hCons = NULL;
  311.     return ICERR_OK;
  312. }
  313. /* */
  314. LRESULT compress( CODEC *codec, ICCOMPRESS *icc )
  315. {
  316.     BITMAPINFOHEADER *inhdr = icc->lpbiInput;
  317.     BITMAPINFOHEADER *outhdr = icc->lpbiOutput;
  318.     x264_picture_t pic;
  319.     int        i_nal;
  320.     x264_nal_t *nal;
  321.     int        i_out;
  322.     int i;
  323.     /* Init the picture */
  324.     memset( &pic, 0, sizeof( x264_picture_t ) );
  325.     pic.img.i_csp = get_csp( inhdr );
  326.     /* For now biWidth can be divided by 16 so no problem */
  327.     switch( pic.img.i_csp & X264_CSP_MASK )
  328.     {
  329.         case X264_CSP_I420:
  330.         case X264_CSP_YV12:
  331.             pic.img.i_plane = 3;
  332.             pic.img.i_stride[0] = inhdr->biWidth;
  333.             pic.img.i_stride[1] =
  334.             pic.img.i_stride[2] = inhdr->biWidth / 2;
  335.             pic.img.plane[0]    = (uint8_t*)icc->lpInput;
  336.             pic.img.plane[1]    = pic.img.plane[0] + inhdr->biWidth * inhdr->biHeight;
  337.             pic.img.plane[2]    = pic.img.plane[1] + inhdr->biWidth * inhdr->biHeight / 4;
  338.             break;
  339.         case X264_CSP_YUYV:
  340.             pic.img.i_plane = 1;
  341.             pic.img.i_stride[0] = 2 * inhdr->biWidth;
  342.             pic.img.plane[0]    = (uint8_t*)icc->lpInput;
  343.             break;
  344.         case X264_CSP_BGR:
  345.             pic.img.i_plane = 1;
  346.             pic.img.i_stride[0] = 3 * inhdr->biWidth;
  347.             pic.img.plane[0]    = (uint8_t*)icc->lpInput;
  348.             break;
  349.         case X264_CSP_BGRA:
  350.             pic.img.i_plane = 1;
  351.             pic.img.i_stride[0] = 4 * inhdr->biWidth;
  352.             pic.img.plane[0]    = (uint8_t*)icc->lpInput;
  353.             break;
  354.         default:
  355.             return ICERR_BADFORMAT;
  356.     }
  357.     /* encode it */
  358.     x264_encoder_encode( codec->h, &nal, &i_nal, &pic, &pic );
  359.     /* create bitstream, unless we're dropping it in 1st pass */
  360.     i_out = 0;
  361.     if( codec->config.i_encoding_type != 2 || codec->config.i_pass > 1 ) {
  362.         for( i = 0; i < i_nal; i++ ) {
  363.             int i_size = outhdr->biSizeImage - i_out;
  364.             x264_nal_encode( (uint8_t*)icc->lpOutput + i_out, &i_size, 1, &nal[i] );
  365.             i_out += i_size;
  366.         }
  367.     }
  368.     outhdr->biSizeImage = i_out;
  369.     /* Set key frame only for IDR, as they are real synch point, I frame
  370.        aren't always synch point (ex: with multi refs, ref marking) */
  371.     if( pic.i_type == X264_TYPE_IDR )
  372.         *icc->lpdwFlags = AVIIF_KEYFRAME;
  373.     else
  374.         *icc->lpdwFlags = 0;
  375.     return ICERR_OK;
  376. }