⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 tvideocodecx264.cpp

📁 从FFMPEG转换而来的H264解码程序,VC下编译..
💻 CPP
字号:
/*
 * Copyright (c) 2004-2006 Milan Cutka
 *
 * This program 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
 * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include "stdafx.h"
#include "TvideoCodecX264.h"
#include "Tdll.h"
#include "ffcodecs.h"
#include "TcodecSettings.h"
#include "x264/x264.h"
#define X264_BFRAME_MAX 16
#include "x264/common/frame.h"
#include "libavcodec/avcodec.h"
#include "IffdshowBase.h"

#pragma warning(disable: 4244)

const char_t* TvideoCodecX264::dllname=_l("ff_x264.dll");

TvideoCodecX264::TvideoCodecX264(IffdshowBase *Ideci,IencVideoSink *Isink):
 Tcodec(Ideci),
 TvideoCodecEnc(Ideci,Isink),
 TvideoCodec(Ideci)
{
 ok=false;
 dll=new Tdll(dllname,config);
 dll->loadFunction(x264_encoder_open   ,"x264_encoder_open"   );
 dll->loadFunction(x264_encoder_headers,"x264_encoder_headers");
 dll->loadFunction(x264_encoder_encode ,"x264_encoder_encode" );
 dll->loadFunction(x264_encoder_close  ,"x264_encoder_close"  );
 dll->loadFunction(x264_param_default  ,"x264_param_default"  );
 dll->loadFunction(x264_picture_alloc  ,"x264_picture_alloc"  );
 dll->loadFunction(x264_picture_clean  ,"x264_picture_clean"  );
 dll->loadFunction(x264_nal_encode     ,"x264_nal_encode"     );
 ok=dll->ok;
 if (ok)
  {
   encoders.push_back(new Tencoder(_l("H.264"),CODEC_ID_X264));
   encoders.push_back(new Tencoder(_l("H.264 lossless"),CODEC_ID_X264_LOSSLESS));
  }
 h=NULL;lossless=false;
}
TvideoCodecX264::~TvideoCodecX264()
{
 end();
 if (dll) delete dll;
}

const char_t* TvideoCodecX264::getName(void) const
{
 tsprintf(codecName,_l("x264%s"),lossless?_l(" lossless"):_l(""));
 return codecName;
}

LRESULT TvideoCodecX264::beginCompress(int cfgcomode,int csp,const Trect &r)
{
 x264_param_t param;
 x264_param_default(&param);

 param.cpu=0;
 if (Tconfig::cpu_flags&FF_CPU_MMX     ) param.cpu|=X264_CPU_MMX;
 if (Tconfig::cpu_flags&FF_CPU_MMXEXT  ) param.cpu|=X264_CPU_MMXEXT;
 if (Tconfig::cpu_flags&FF_CPU_SSE     ) param.cpu|=X264_CPU_SSE;
 if (Tconfig::cpu_flags&FF_CPU_SSE2    ) param.cpu|=X264_CPU_SSE2;
 if (Tconfig::cpu_flags&FF_CPU_SSSE3   ) param.cpu|=X264_CPU_SSSE3;
 if (Tconfig::cpu_flags&FF_CPU_3DNOW   ) param.cpu|=X264_CPU_3DNOW;
 if (Tconfig::cpu_flags&FF_CPU_3DNOWEXT) param.cpu|=X264_CPU_3DNOWEXT;

 /* Video Properties */
 param.i_width =r.dx;
 param.i_height=r.dy;

 /* they will be reduced to be 0 < x <= 65535 and prime */
 Rational sar=coCfg->sar(r.dx,r.dy);
 param.vui.i_sar_width=sar.num;
 param.vui.i_sar_height=sar.den;

 /* Used for rate control only */
 param.i_fps_num=deci->getParam2(IDFF_enc_fpsRate);param.i_fps_den=deci->getParam2(IDFF_enc_fpsScale);

 // Maximum number of reference frames
 param.i_frame_reference=coCfg->x264_max_ref_frames;

 // every i_iframe are intra
 param.i_keyint_max=coCfg->max_key_interval;
 param.i_keyint_min=coCfg->min_key_interval;

 if (sup_bframes(coCfg->codecId) && coCfg->isBframes)
  {
   // how many b-frame between 2 references pictures
   param.i_bframe=coCfg->max_b_frames;
   if (coCfg->max_b_frames>1)
   param.analyse.b_weighted_bipred=1;
   param.analyse.i_direct_mv_pred=coCfg->x264_i_direct_mv_pred;
   param.analyse.i_direct_8x8_inference=-1;
   param.b_bframe_adaptive=coCfg->b_dynamic;
   param.b_bframe_pyramid=coCfg->x264_b_bframe_pyramid;
   param.analyse.b_bidir_me=coCfg->b_refine;
  }

 param.b_deblocking_filter=coCfg->codecId!=CODEC_ID_X264_LOSSLESS && (coCfg->H263Pflags&CODEC_FLAG_LOOP_FILTER)?1:0;
 param.i_deblocking_filter_alphac0=coCfg->x264_i_deblocking_filter_alphac0;
 param.i_deblocking_filter_beta=coCfg->x264_i_deblocking_filter_beta;
 param.b_cabac=coCfg->x264_cabac;
 param.b_interlaced=coCfg->x264_interlaced;

 param.analyse.inter=coCfg->x264_me_inter;
 param.analyse.intra=coCfg->x264_me_intra;
 if ((param.analyse.inter|param.analyse.intra)&X264_ANALYSE_I8x8)
  param.analyse.b_transform_8x8=1;
 param.analyse.i_subpel_refine=coCfg->x264_me_subpelrefine;
 param.analyse.i_mv_range=coCfg->x264_mv_range;
 param.analyse.i_mv_range_thread=-1;
 param.analyse.i_me_method=coCfg->x264_me_method;
 if (coCfg->x264_me_method>=2)
  param.analyse.i_me_range=coCfg->x264_me_range;
 param.analyse.b_chroma_me=coCfg->me_cmp_chroma;
 param.analyse.b_mixed_references=coCfg->x264_mixed_ref;
 param.analyse.b_dct_decimate=coCfg->x264_b_dct_decimate;
 param.i_threads=coCfg->numthreads;
 param.b_deterministic=0;

 if (coCfg->codecId==CODEC_ID_X264_LOSSLESS)
  {
   lossless=true;
   param.rc.i_qp_constant=0;
  }
 else
  {
   if (coCfg->mode==ENC_MODE::CBR || coCfg->mode==ENC_MODE::VBR_QUAL)
    {
     param.rc.i_rc_method=X264_RC_ABR;
     param.rc.i_bitrate=coCfg->bitrate1000;
     param.rc.i_qp_min=coCfg->limitq(coCfg->q_p_min);
     param.rc.i_qp_max=coCfg->limitq(coCfg->q_p_max);
     param.rc.f_qcompress=coCfg->ff1_vqcomp/100.0f;
     param.rc.f_qblur=(coCfg->ff1_stats_mode&FFSTATS::WRITE?coCfg->ff1_vqblur2:coCfg->ff1_vqblur1)/100.0f;
     param.rc.i_qp_constant=0;
     if (coCfg->mode==ENC_MODE::VBR_QUAL)
      param.rc.i_rc_method=X264_RC_CRF;
      param.rc.f_rf_constant=50*(100-coCfg->qual)/100+1;
     //param.analyse.b_aq=coCfg->x264_is_aq;
     //param.analyse.f_aq_strength=coCfg->x264_aq_strength100/100.0f;
     //param.analyse.f_aq_sensitivity=(float)coCfg->x264_f_aq_sensitivity;
    }
   else
    {
     param.rc.i_rc_method=X264_RC_CQP;
     param.rc.i_qp_constant=coCfg->limitq(coCfg->quant);
     param.rc.f_ip_factor=1.0f;
     param.rc.f_pb_factor=1.0f;
    }
   param.analyse.i_trellis=coCfg->trellisquant;
   if (coCfg->is_lavc_nr) param.analyse.i_noise_reduction=coCfg->lavc_nr;
   if (coCfg->quant_type==5)
    param.i_cqm_preset=X264_CQM_JVT;
   else if (coCfg->quant_type==4)
    {
     param.i_cqm_preset=X264_CQM_CUSTOM;
     memcpy(param.cqm_4iy,&coCfg->qmatrix_intra4x4Y_custom0,16);
     memcpy(param.cqm_4py,&coCfg->qmatrix_inter4x4Y_custom0,16);
     memcpy(param.cqm_4ic,&coCfg->qmatrix_intra4x4C_custom0,16);
     memcpy(param.cqm_4pc,&coCfg->qmatrix_inter4x4C_custom0,16);
     memcpy(param.cqm_8iy,&coCfg->qmatrix_intra_custom0,64);
     memcpy(param.cqm_8py,&coCfg->qmatrix_inter_custom0,64);
    }
  }

 param.analyse.b_psnr=deci->getParam2(IDFF_enc_psnr);
 param.analyse.b_ssim=0;
 if (coCfg->ff1_stats_mode&FFSTATS::READ && cfgcomode==ENC_MODE::CBR)
  {
   param.rc.b_stat_read=1;
   param.rc.psz_stat_in=(char*)coCfg->ff1_stats_flnm;
   if (coCfg->ff1_stats_mode==FFSTATS::RW)
    param.rc.b_stat_write=1;
  }
 if (coCfg->ff1_stats_mode&FFSTATS::WRITE)
  {
   param.rc.b_stat_write=1;
   param.rc.psz_stat_out=(char*)coCfg->ff1_stats_flnm;
  }
 param.i_log_level=X264_LOG_NONE;
 param.b_aud=coCfg->x264_b_aud;

 x264_zone_t zones[2];int zonescount=0;
 if (coCfg->isCreditsStart && cfgcomode==ENC_MODE::CBR)
  {
   x264_zone_t &zone=zones[zonescount];
   zone.i_start=coCfg->creditsStartBegin;
   zone.i_end=coCfg->creditsStartEnd;
   switch (coCfg->credits_mode)
    {
     case CREDITS_MODE::QUANT:zone.i_qp=coCfg->limitq(coCfg->credits_quant_i);zone.b_force_qp=1;break;
     case CREDITS_MODE::PERCENT:zone.b_force_qp=0;zone.f_bitrate_factor=coCfg->credits_percent/100.0f;break;
    }
   zonescount++;
  }
 if (coCfg->isCreditsEnd && cfgcomode==ENC_MODE::CBR)
  {
   x264_zone_t &zone=zones[zonescount];
   zone.i_start=coCfg->creditsEndBegin;
   zone.i_end=coCfg->creditsEndEnd;
   switch (coCfg->credits_mode)
    {
     case CREDITS_MODE::QUANT:zone.i_qp=coCfg->limitq(coCfg->credits_quant_i);zone.b_force_qp=1;break;
     case CREDITS_MODE::PERCENT:zone.b_force_qp=0;zone.f_bitrate_factor=coCfg->credits_percent/100.0f;break;
    }
   zonescount++;
  }
 if ((param.rc.i_zones=zonescount)!=0)
  param.rc.zones=zones;

 h=x264_encoder_open(&param);
 if (!h) return ICERR_ERROR;
 return ICERR_OK;
}
void TvideoCodecX264::fill_x264_pict(x264_frame_t *out,const TffPict *in)
{
 TffPict::copy(out->plane[0],out->i_stride[0],in->data[0],in->stride[0],in->rectFull.dx  ,in->rectFull.dy  );
 TffPict::copy(out->plane[1],out->i_stride[1],in->data[1],in->stride[1],in->rectFull.dx/2,in->rectFull.dy/2);
 TffPict::copy(out->plane[2],out->i_stride[2],in->data[2],in->stride[2],in->rectFull.dx/2,in->rectFull.dy/2);

 out->i_type=X264_TYPE_AUTO;
 out->i_qpplus1=0;
}
HRESULT TvideoCodecX264::compress(const TffPict &pict,TencFrameParams &params)
{
 int i_nal;
 x264_nal_t *nal;
 x264_picture_t pic_out;
again:
 if (x264_encoder_encode(h,&nal,&i_nal,pict.data[0]?(void*)fill_x264_pict:NULL,&pict,&pic_out)<0)
  return sinkE->deliverError();
 if (!pict.data[0] && i_nal==0)
  return S_OK;
 params.length=0;

 TmediaSample sample;
 HRESULT hr;
 if (FAILED(hr=sinkE->getDstBuffer(&sample,pict)))
  return hr;
 uint8_t *dst=sample;size_t dstLen=sample.size();
 for(int i=0;i<i_nal;i++)
  {
   int i_data=(int)dstLen,i_size;
   if ((i_size=x264_nal_encode(dst,&i_data,1,&nal[i]))>0)
    {
     dst+=i_size;
     dstLen-=i_size;
     params.length+=i_size;;
    }
   else if(i_size<0)
    return sinkE->deliverError();
  }
 switch (pic_out.i_type)
  {
   case X264_TYPE_IDR:
   case X264_TYPE_I:
    params.frametype=FRAME_TYPE::I;
    params.keyframe=pic_out.i_type==X264_TYPE_IDR || (pic_out.i_type==X264_TYPE_I && coCfg->x264_max_ref_frames==1);
    break;
   case X264_TYPE_P:
    params.frametype=FRAME_TYPE::P;
    break;
   case X264_TYPE_B:
   case X264_TYPE_BREF:
    params.frametype=FRAME_TYPE::B;
    break;
   default:
    params.frametype=FRAME_TYPE::DELAY;
    break;
  }
 if (params.frametype!=FRAME_TYPE::UNKNOWN)
  {
   if (coCfg->mode==ENC_MODE::CBR || coCfg->mode==ENC_MODE::VBR_QUAL)
    params.quant=pic_out.i_qpplus1;
   params.psnrY=pic_out.i_sqe_y;
   params.psnrU=pic_out.i_sqe_u;
   params.psnrV=pic_out.i_sqe_v;
  }
 if (FAILED(hr=sinkE->deliverEncodedSample(sample,params)))
  return hr;
 if (!pict.data[0])
  goto again;
 return hr;
}

void TvideoCodecX264::end(void)
{
 if (ok)
  {
   if (h) x264_encoder_close(h);h=NULL;
  }
 lossless=false;
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -