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

📄 timgfilteravisynth.cpp

📁 从FFMPEG转换而来的H264解码程序,VC下编译..
💻 CPP
📖 第 1 页 / 共 3 页
字号:
/*
 * Copyright (c) 2002-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 "TimgFilterAvisynth.h"
#include "IffdshowBase.h"
#include "IffdshowDecVideo.h"
#include "Tconvert.h"
#include "ffdebug.h"

bool debugPrint=false;
int maxBufferAhead=0;
int maxBufferBack=0;

//========================== TimgFilterAvisynth::Tffdshow_source ===============================
AVS_Value AVSC_CC TimgFilterAvisynth::Tffdshow_source::Create(AVS_ScriptEnvironment *env, AVS_Value args, void *user_data)
{
 Tinput* input=(Tinput*)user_data;
 AVS_Value v;
 AVS_FilterInfo *fi;
 AVS_Clip *new_clip=input->env->avs_new_c_filter(*input->env,&fi,args,0);
 Tffdshow_source *filter=new Tffdshow_source(input,(VideoInfo&)fi->vi);

 fi->user_data=filter;
 fi->get_frame=get_frame;
 fi->get_parity=get_parity;
 fi->set_cache_hints=set_cache_hints;
 fi->free_filter=free_filter;

 input->env->avs_set_to_clip(&v, new_clip);
 input->env->avs_release_clip(new_clip);

 return v;
}

void AVSC_CC TimgFilterAvisynth::Tffdshow_source::free_filter(AVS_FilterInfo *fi)
{
 if (fi && fi->user_data)
  delete (Tffdshow_source*)fi->user_data;
}

TimgFilterAvisynth::Tffdshow_source::Tffdshow_source(Tinput *Iinput,VideoInfo &Ivi):
 input(Iinput),
 vi(Ivi)
{
 memset(&vi,0,sizeof(VideoInfo));
 vi.width=input->dx;
 vi.height=input->dy;
 vi.fps_numerator=input->fpsnum;
 vi.fps_denominator=input->fpsden;
 vi.num_frames=NUM_FRAMES;

 if      (input->csp & FF_CSP_420P)  vi.pixel_type=AVS_CS_YV12;
 else if (input->csp & FF_CSP_YUY2)  vi.pixel_type=AVS_CS_YUY2;
 else if (input->csp & FF_CSP_RGB32) vi.pixel_type=AVS_CS_BGR32;
 else if (input->csp & FF_CSP_RGB24) vi.pixel_type=AVS_CS_BGR24;
}

int TimgFilterAvisynth::findBuffer(TframeBuffer* buffers, int numBuffers, int n)
 {
  // Find the index of the buffer that's framenumber is closest (or equal to) n

  int minDistance=MAX_INT;
  int bestBufferNo=0;

  if (buffers && numBuffers > 1)
   for (int bufferNo=0; bufferNo < numBuffers; bufferNo++)
    {
     TframeBuffer& buffer=buffers[bufferNo];

     if (buffer.frameNo < 0)
      continue;
     else if (buffer.frameNo == n)
      {
       bestBufferNo=bufferNo;

       break;
      }

     int distance=abs(buffer.frameNo-n);

     if (distance < minDistance)
      {
       minDistance=distance;
       bestBufferNo=bufferNo;
      }
    }

  return bestBufferNo;
 }

AVS_VideoFrame* AVSC_CC TimgFilterAvisynth::Tffdshow_source::get_frame(AVS_FilterInfo *fi, int n)
{
 Tffdshow_source *filter=(Tffdshow_source*)fi->user_data;
 Tinput* input=filter->input;
 PVideoFrame frame(input->env,input->env->avs_new_video_frame_a(*input->env,&filter->vi,16));

 // Calculate request statistics for currently produced frame

 int curFrameDistance=(n >= input->backLimit ? n : input->backLimit)-input->curFrame;

 if (input->numAccessedFrames < 100)
  input->accessedFrames[input->numAccessedFrames]=curFrameDistance;

 if (input->minAccessedFrame > curFrameDistance)
  input->minAccessedFrame=curFrameDistance;

 if (input->maxAccessedFrame < curFrameDistance)
  input->maxAccessedFrame=curFrameDistance;

 input->numAccessedFrames++;

 // Find the buffered frame that's closest to n and return it

 if (input->numBuffers > 0)
  {
   TframeBuffer& buffer=input->buffers[findBuffer(input->buffers,input->numBuffers,n)];

   if (debugPrint)
    DPRINTF(_l("TimgFilterAvisynth: Looked up frame %i, using frame %i"),n,buffer.frameNo);

   switch (filter->input->csp&FF_CSPS_MASK)
    {
     case FF_CSP_420P:
      TffPict::copy(frame->GetWritePtr(PLANAR_Y),frame->GetPitch(PLANAR_Y),buffer.data[0],buffer.pitch[0],buffer.width[0],buffer.height[0]);
      TffPict::copy(frame->GetWritePtr(PLANAR_U),frame->GetPitch(PLANAR_U),buffer.data[1],buffer.pitch[1],buffer.width[1],buffer.height[1]);
      TffPict::copy(frame->GetWritePtr(PLANAR_V),frame->GetPitch(PLANAR_V),buffer.data[2],buffer.pitch[2],buffer.width[2],buffer.height[2]);
      break;

     case FF_CSP_YUY2:
      TffPict::copy(frame->GetWritePtr(),frame->GetPitch(),buffer.data[0],buffer.pitch[0],buffer.width[0]*buffer.bytesPerPixel,buffer.height[0]);
      break;

     case FF_CSP_RGB24:
     case FF_CSP_RGB32:
      TffPict::copy(frame->GetWritePtr(),frame->GetPitch(),buffer.data[0]+buffer.pitch[0]*(buffer.height[0]-1),-buffer.pitch[0],buffer.width[0]*buffer.bytesPerPixel,buffer.height[0]);
      break;
    }
  }
 else
  {
   int count;
   unsigned long* dest;

   if (debugPrint)
    DPRINTF(_l("TimgFilterAvisynth: Looked up frame %i, but no frames were buffered"),n);

   switch (filter->input->csp&FF_CSPS_MASK)
    {
     case FF_CSP_420P:
      memset(frame->GetWritePtr(PLANAR_Y),0,frame->GetPitch(PLANAR_Y)*frame->GetHeight(PLANAR_Y));
      memset(frame->GetWritePtr(PLANAR_U),128,frame->GetPitch(PLANAR_U)*frame->GetHeight(PLANAR_U));
      memset(frame->GetWritePtr(PLANAR_V),128,frame->GetPitch(PLANAR_V)*frame->GetHeight(PLANAR_V));

      break;

     case FF_CSP_YUY2:
      for (dest=(unsigned long*)frame->GetWritePtr(),
           count=frame->GetPitch()*frame->GetHeight();
           count > 0;
           dest++,
           count-=sizeof(unsigned long))
       *dest=0x80008000;

      break;

     case FF_CSP_RGB24:
     case FF_CSP_RGB32:
      memset(frame->GetWritePtr(),0,frame->GetPitch()*frame->GetHeight());

      break;
    }
  }

 return frame;
}

//============================= TimgFilterAvisynth::Tffdshow_setAR =============================

AVS_Value AVSC_CC TimgFilterAvisynth::Tffdshow_setAR::Create_SetSAR(AVS_ScriptEnvironment *env, AVS_Value args, void * user_data)
{
 return Create(env,args,user_data,false);
}

AVS_Value AVSC_CC TimgFilterAvisynth::Tffdshow_setAR::Create_SetDAR(AVS_ScriptEnvironment *env, AVS_Value args, void * user_data)
{
 return Create(env,args,user_data,true);
}

AVS_Value AVSC_CC TimgFilterAvisynth::Tffdshow_setAR::Create(AVS_ScriptEnvironment *env, AVS_Value args, void * user_data, bool setDAR)
{
 Tinput* input=(Tinput*)user_data;
 int x=avs_as_int(avs_array_elt(args,0));
 int y=avs_as_int(avs_array_elt(args,1));

 input->outputSar=( setDAR ? Rational(0,0) : Rational(x,y));
 input->outputDar=(!setDAR ? Rational(0,0) : Rational(x,y));

 return avs_void;
}

//================================ TimgFilterAvisynth::Tavisynth ===============================
bool TimgFilterAvisynth::Tavisynth::createClip(const TavisynthSettings *cfg,Tinput *input,TffPictBase& pict)
{
 if (!input->env)
  {
   input->env=CreateScriptEnvironment(AVISYNTH_INTERFACE_VERSION);

   if (!input->env)
    return false;

   input->env->AddFunction(
    "ffdshow_source",
    "",
    TimgFilterAvisynth::Tffdshow_source::Create,
    (void*)input);

   input->env->AddFunction(
    "ffdshow_setSAR",
    "[x]i[y]i",
    TimgFilterAvisynth::Tffdshow_setAR::Create_SetSAR,
    (void*)input);

   input->env->AddFunction(
    "ffdshow_setDAR",
    "[x]i[y]i",
    TimgFilterAvisynth::Tffdshow_setAR::Create_SetDAR,
    (void*)input);
  }

 IScriptEnvironment* env=input->env;

 Rational sar=pict.rectClip.sar;
 Rational dar=pict.rectClip.dar();

 env->SetGlobalVar("ffdshow_sar_x",AVSValue(sar.num));
 env->SetGlobalVar("ffdshow_sar_y",AVSValue(sar.den));
 env->SetGlobalVar("ffdshow_dar_x",AVSValue(dar.num));
 env->SetGlobalVar("ffdshow_dar_y",AVSValue(dar.den));

 char script[2048];

 // Convert script to ASCII; add ffdshow_source if the option for it is checked
 _snprintf(
  script,
  sizeof(script)-1,
  "%s%s%s",
  cfg->ffdshowSource ? "ffdshow_source()\n" : "",
  (const char*)text<char>(cfg->script),
  cfg->ffdshowSource ? "\nreturn last" : "");

 script[sizeof(script)-1]=0;

 try
  {
   // Try using the script

   AVSValue eval_args[]={script,"ffdshow_filter_avisynth_script"};
   AVSValue val=env->Invoke("Eval",AVSValue(eval_args,2));

   if (val.IsClip())
    {
     input->clip=new PClip(val,env);

     return true;
    }
   else
    throw AvisynthError("Invalid script!");
  }
 catch (AvisynthError &err)
  {
   // Create another script that contains only the source with the error subtitled onto it
   char errMsg[1024];

   _snprintf(errMsg,1023,"%s",(const char*)text<char>(err.msg)); errMsg[1023]=0;

   for (char* errPtr=errMsg; *errPtr; errPtr++)
    if (*errPtr == '\"')
     *errPtr='\'';
    else if (*errPtr == '\n')
     *errPtr=' ';

   _snprintf(script,2047,"return ffdshow_source().Subtitle(\"%s\")",errMsg);

   try
    {
     // Try using that script

     AVSValue err_eval_args[]={script,"ffdshow_filter_avisynth_error_script"};
     AVSValue val=env->Invoke("Eval",AVSValue(err_eval_args,2));

     if (val.IsClip())
      {
       input->clip=new PClip(val,env);

       return true;
      }
     else
      throw err;
    }
   catch (AvisynthError)
    {
     // Oh well...
     throw err;
    }
  }
}

void TimgFilterAvisynth::Tavisynth::setOutFmt(const TavisynthSettings *cfg,Tinput *input,TffPictBase &pict)
{
 if ((pict.rectClip == inputRect) && !(pict.rectClip.dar() != inputDar)) // No operator== in Rational... o_O;
  {
   if (outputRect != inputRect)
    pict.rectFull=pict.rectClip=outputRect;
  }
 else if (createClip(cfg,input,pict))
  {
   IScriptEnvironment* env=input->env;

   inputRect=pict.rectClip;
   inputSar=pict.rectClip.sar;
   inputDar=pict.rectClip.dar();

   const VideoInfo &vi=(*input->clip)->GetVideoInfo();

   if (input->outputDar)
    pict.rectFull=pict.rectClip=outputRect=
     Trect(
      0,0,vi.width,vi.height,
      Rational((vi.height*input->outputDar.num)/double(vi.width*input->outputDar.den),32768));
   else if (input->outputSar)
    pict.rectFull=pict.rectClip=outputRect=Trect(0,0,vi.width,vi.height,input->outputSar);
   else if ((unsigned int)vi.width != inputRect.dx || (unsigned int)vi.height != inputRect.dy)
    pict.rectFull=pict.rectClip=outputRect=Trect(0,0,vi.width,vi.height,inputSar);
   else
    outputRect=inputRect;

   delete input->clip; input->clip=0;
  }
}

void TimgFilterAvisynth::Tavisynth::skipAhead(bool passFirstThrough, bool clearLastOutStopTime)
{
 // Skip ahead at least 1000 frames to make sure AviSynth doesn't use buffered frames,
 // then round the new frame numbers up to make sure the relative alignment between the
 // different framenumbers stays the same
 // (Don't skip if buffering is turned off, though...)

 int skippedFrames=(numBuffers > (applyPulldown == 1 ? 2 : 1) ? 1000 : 0);
 REFERENCE_TIME roundToLong=frameScaleNum*frameScaleNum*frameScaleDen;
 int roundTo=(int)(roundToLong > NUM_FRAMES ? NUM_FRAMES : roundToLong);

 curInFrameNo=curInFrameNo+skippedFrames+(roundTo-1);
 curInFrameNo-=curInFrameNo%roundTo;

 if (curInFrameNo > TimgFilterAvisynth::NUM_FRAMES/2)
  // Make sure we don't actually hit the end of the AviSynth clip
  curInFrameNo=0;

 backLimit=curInFrameNo;

 curOutFrameNo=(int)(((REFERENCE_TIME)curInFrameNo)*frameScaleDen/frameScaleNum);
 curOutScaledFrameNo=curInFrameNo;

 if (clearLastOutStopTime)
  lastOutStopTime=0;

 resetBuffers=true;
 this->passFirstThrough=passFirstThrough;
}

void TimgFilterAvisynth::Tavisynth::done(void)
{
 if (bufferData) delete bufferData; bufferData=0;
 if (buffers) delete buffers; buffers=0;
}

void TimgFilterAvisynth::Tavisynth::init(const TavisynthSettings &oldcfg, Tinput* input,int *outcsp, TffPictBase& pict)
{
 infoBuf[0]=0;

 if (createClip(&oldcfg,input,pict))
  {
   const VideoInfo &vi=(*input->clip)->GetVideoInfo();
   if      (vi.IsRGB24()) *outcsp=FF_CSP_RGB24|FF_CSP_FLAGS_VFLIP;
   else if (vi.IsRGB32()) *outcsp=FF_CSP_RGB32|FF_CSP_FLAGS_VFLIP;
   else if (vi.IsYUY2())  *outcsp=FF_CSP_YUY2;
   else if (vi.IsYV12())  *outcsp=FF_CSP_420P;
   else                   *outcsp=FF_CSP_NULL;

   applyPulldown=oldcfg.applyPulldown;

   enableBuffering=!!oldcfg.enableBuffering;
   bufferAhead=(enableBuffering ? oldcfg.bufferAhead : 0);
   bufferBack=(enableBuffering ? oldcfg.bufferBack : 0);

   if (bufferAhead == 0 && bufferBack == 0)
    enableBuffering=false;

   buffersNeeded=bufferAhead+1;
   input->numBuffers=numBuffers=
    buffersNeeded+
    bufferBack+
    (enableBuffering && vi.num_frames != NUM_FRAMES ? 1 : 0)+
    (applyPulldown == 1 ? 1 : 0);

   curInFrameNo=0;
   curOutFrameNo=0;
   curOutScaledFrameNo=0;
   backLimit=0;

   lastOutStopTime=-1;

   frameScaleNum=REFERENCE_TIME(NUM_FRAMES);
   frameScaleDen=REFERENCE_TIME(vi.num_frames);

   REFERENCE_TIME frameScaleGCD=lavc_gcd(frameScaleNum,frameScaleDen);

   frameScaleNum/=frameScaleGCD;
   frameScaleDen/=frameScaleGCD;

   inputRect=pict.rectClip;
   inputSar=pict.rectClip.sar;
   inputDar=pict.rectClip.dar();

   if (input->outputDar)
    pict.rectFull=pict.rectClip=outputRect=
     Trect(
      0,0,vi.width,vi.height,
      Rational((vi.height*input->outputDar.num)/double(vi.width*input->outputDar.den),32768));
   else if (input->outputSar)

⌨️ 快捷键说明

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