timgfiltersubtitles.cpp

来自「从FFMPEG转换而来的H264解码程序,VC下编译..」· C++ 代码 · 共 382 行

CPP
382
字号
/*
 * 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 "TimgFilterSubtitles.h"
#include "TsubtitlesSettings.h"
#include "IffdshowBase.h"
#include "IffdshowDecVideo.h"
#include "TimgFilterExpand.h"
#include "TglobalSettings.h"
#include "TimgFilters.h"
#include "Tsubtitle.h"
#include "TsubtitleText.h"
#include "Tsubreader.h"
#include "TsubtitlesTextpin.h"

TimgFilterSubtitles::TsubPrintPrefs::TsubPrintPrefs(unsigned char *Idst[4],stride_t Istride[4],unsigned int Idx[4],unsigned int Idy[4],IffdshowBase *Ideci,const TsubtitlesSettings *cfg,const TffPict &pict,const Tconfig *Iconfig,bool Idvd):TrenderedSubtitleLines::TprintPrefs(Ideci)
{
 dst=Idst;
 stride=Istride;
 shiftX=pict.cspInfo.shiftX;shiftY=pict.cspInfo.shiftY;
 dx=Idx[0];
 dy=Idy[0];
 xpos=cfg->posX;
 ypos=cfg->posY;
 align=cfg->align;
 linespacing=cfg->linespacing;
 vobchangeposition=!!cfg->vobsubChangePosition;
 vobscale=cfg->vobsubScale;
 vobaamode=cfg->vobsubAA;
 vobaagauss=cfg->vobsubAAswgauss;
 textBorderLR=2*cfg->splitBorder;
 deci=Ideci;
 config=Iconfig;
 dvd=Idvd;
 // Copy subtitles shadow vars
 int i;
 deci->getParam(IDFF_fontShadowMode, &shadowMode);
 deci->getParam(IDFF_fontShadowSize, &i);
 shadowSize=i;
 deci->getParam(IDFF_fontShadowAlpha, &shadowAlpha);
}

TimgFilterSubtitles::TimgFilterSubtitles(IffdshowBase *Ideci,Tfilters *Iparent):
 TimgFilter(Ideci,Iparent),
 font(Ideci),fontCC(Ideci),
 subs(Ideci),
 oldFontCfg((TfontSettingsSub*)malloc(sizeof(TfontSettingsSub))),
 oldFontCCcfg((TfontSettingsSub*)malloc(sizeof(TfontSettingsSub))),
 cc(NULL),wasCCchange(true)
{
 oldFontCfg->weight=oldFontCCcfg->weight=-1;oldstereo=oldsplitborder=-1;
 AVIfps=-1;
 expand=NULL;
 expandSizeChanged=fontSizeChanged=true;oldExpandCode=-1;
 oldSizeDx=oldSizeDy=0;
 isdvdproc=false;
 wasDiscontinuity=true;
 again=false;
 prevCfg=NULL;
 subFlnmChanged=1;
}
TimgFilterSubtitles::~TimgFilterSubtitles()
{
 if (expand) delete expand;
 for (Tembedded::iterator e=embedded.begin();e!=embedded.end();e++)
  if (e->second)
   delete e->second;
 ::free(oldFontCfg);::free(oldFontCCcfg);
 if (cc) delete cc;
}

void TimgFilterSubtitles::onSizeChange(void)
{
 expandSizeChanged=fontSizeChanged=true;
}
void TimgFilterSubtitles::onSubFlnmChange(int id,int)
{
 subFlnmChanged=id?id:-1;
}
void TimgFilterSubtitles::onSubFlnmChangeStr(int id,const char_t*)
{
 subFlnmChanged=id?id:-1;
}

bool TimgFilterSubtitles::is(const TffPictBase &pict,const TfilterSettingsVideo *cfg)
{
 isdvdproc=deci->getParam2(IDFF_dvdproc);
 return isdvdproc || super::is(pict,cfg);
}

bool TimgFilterSubtitles::getOutputFmt(TffPictBase &pict,const TfilterSettingsVideo *cfg0)
{
 if (super::getOutputFmt(pict,cfg0))
  {
   const TsubtitlesSettings *cfg=(const TsubtitlesSettings*)cfg0;
   isdvdproc=deci->getParam2(IDFF_dvdproc);
   if (cfg->isExpand && cfg->expandCode && !isdvdproc)
    {
     const char_t *subflnm=cfg->autoFlnm?findAutoSubFlnm(cfg):cfg->flnm;
     if ((subflnm[0]=='\0' || !fileexists(subflnm)) && !deci->getParam2(IDFF_subTextpin)) return true;
     if (!expand) expand=new TimgFilterExpand(deci,parent);
     int a1,a2;
     cfg->getExpand(&a1,&a2);
     Trect::calcNewSizeAspect(pict.rectFull,a1,a2,expandSettings.newrect);
     expand->getOutputFmt(pict,&expandSettings);
    }
   return true;
  }
 else
  return false;
}

bool TimgFilterSubtitles::initSubtitles(int id,int type,const unsigned char *extradata,unsigned int extradatalen)
{
 csEmbedded.Lock();
 Tembedded::iterator e=embedded.find(id);
 if (e!=embedded.end())
  {
   delete e->second;
   e->second=TsubtitlesTextpin::create(type,extradata,extradatalen,deci);
  }
 else
  {
   e=embedded.insert(std::make_pair(id,TsubtitlesTextpin::create(type,extradata,extradatalen,deci))).first;
  }
 csEmbedded.Unlock();
 if(!e->second)
  return false;
 return *e->second;
}
void TimgFilterSubtitles::addSubtitle(int id,REFERENCE_TIME start,REFERENCE_TIME stop,const unsigned char *data,unsigned int datalen,const TsubtitlesSettings *cfg,bool utf8)
{
 Tembedded::iterator e=embedded.find(id);
 if (e==embedded.end()) return;
 csEmbedded.Lock();
 e->second->setModified();
 e->second->addSubtitle(start,stop,data,datalen,cfg,utf8);
 csEmbedded.Unlock();
}
void TimgFilterSubtitles::resetSubtitles(int id)
{
 Tembedded::iterator e=embedded.find(id);
 if (e==embedded.end()) return;
 csEmbedded.Lock();
 e->second->resetSubtitles();
 csEmbedded.Unlock();
}
bool TimgFilterSubtitles::ctlSubtitles(int id,int type,unsigned int ctl_id,const void *ctl_data,unsigned int ctl_datalen)
{
 Tembedded::iterator e=embedded.find(id);
 if (e==embedded.end())
  e=embedded.insert(std::make_pair(id,TsubtitlesTextpin::create(type,NULL,0,deci))).first;
 csEmbedded.Lock();
 bool res=e->second->ctlSubtitles(ctl_id,ctl_data,ctl_datalen);
 csEmbedded.Unlock();
 if (res && prevCfg)
  {
   again=true;
   TffPict pict=prevPict;
   process(prevIt,pict,prevCfg);
   again=false;
  }
 return res;
}

const char_t* TimgFilterSubtitles::findAutoSubFlnm(const TsubtitlesSettings *cfg)
{
 struct TcheckSubtitle : IcheckSubtitle
  {
  private:
   TsubtitlesFile subs;
   const TsubtitlesSettings *cfg;
   double fps;
  public:
   TcheckSubtitle(IffdshowBase *deci,const TsubtitlesSettings *Icfg,double Ifps):subs(deci),cfg(Icfg),fps(Ifps) {}
   STDMETHODIMP checkSubtitle(const char_t *subFlnm)
    {
     return subs.init(cfg,subFlnm,fps,false,2);
    }
  } checkSubtitle(deci,cfg,25);
 return deciV->findAutoSubflnms(&checkSubtitle);
}

HRESULT TimgFilterSubtitles::process(TfilterQueue::iterator it,TffPict &pict,const TfilterSettingsVideo *cfg0)
{
 const TsubtitlesSettings *cfg=(const TsubtitlesSettings*)cfg0;

 if (cfg->isExpand && cfg->expandCode && !isdvdproc)
  {
   Trect newExpandRect=cfg->full?pict.rectFull:pict.rectClip;
   if (expandSizeChanged || oldExpandCode!=cfg->expandCode || oldExpandRect!=newExpandRect)
    {
     oldExpandCode=cfg->expandCode;oldExpandRect=newExpandRect;
     if (expand) delete expand;expand=NULL;
     TffPict newpict;newpict.rectFull=pict.rectFull;newpict.rectClip=pict.rectClip;
     getOutputFmt(newpict,cfg);
     parent->dirtyBorder=1;
     expandSizeChanged=false;
    }
   if (expand)
    expand->process(NULL,pict,&expandSettings);
  }

 if (AVIfps==-1) AVIfps=deciV->getAVIfps1000_2()/1000.0;
 if (subFlnmChanged)
  {
   const char_t *subflnm=cfg->autoFlnm?findAutoSubFlnm(cfg):cfg->flnm;
   if (subFlnmChanged!=-1 || stricmp(subflnm,subs.subFlnm)!=0)
    subs.init(cfg,subflnm,AVIfps,!!deci->getParam2(IDFF_subWatch),false);
   subFlnmChanged=0;
  }
 if (subs || !embedded.empty())
  {
   REFERENCE_TIME frameStart=cfg->speed2*((pict.rtStart-parent->subtitleResetTime)-cfg->delay*(REF_SECOND_MULT/1000))/cfg->speed;
   bool forceChange=false;
   const Tsubtitle *sub=NULL;
   csEmbedded.Lock();
   int shownEmbedded=deci->getParam2(IDFF_subShowEmbedded);
   bool useembedded=!embedded.empty() && shownEmbedded;
   if (useembedded)
    {
     Tembedded::iterator e=embedded.find(shownEmbedded);
     if (e!=embedded.end() && e->second)
      {
       if (!e->second->IsProcessOverlapDone())
        e->second->processOverlap();
       sub=e->second->getSubtitle(cfg,frameStart,&forceChange);
      }
    }
   if (!useembedded)
    sub=subs.getSubtitle(cfg,frameStart,&forceChange);
   if (sub)
    {
     if (!again)
      init(pict,cfg->full,cfg->half);
     if (memcmp(oldFontCfg->name,cfg->font.name,sizeof(TfontSettingsSub)-sizeof(Toptions))!=0 || fontSizeChanged || oldstereo!=cfg->stereoscopic || oldsplitborder!=cfg->splitBorder)
      {
       memcpy(oldFontCfg,&cfg->font,sizeof(cfg->font));oldstereo=cfg->stereoscopic;oldsplitborder=cfg->splitBorder;
       font.init(oldFontCfg);
      }
     fontSizeChanged=false;

     /*
     if (isdvdproc)
      {
       if (!again || !prevCfg)
        {
         prevIt=it;
         prevCfg=cfg;
         prevPict=pict;
         pict.setRO(true);
         prevPict.copyFrom(pict,prevbuf);
        }
       else
        {
         pict=prevPict;
         pict.setRO(true);
        }
      }*/
     unsigned char *dst[4];
     getCurNext(FF_CSP_420P,pict,cfg->full,COPYMODE_DEF,dst);
     unsigned int sizeDx,sizeDy;
     if (cfg->font.autosizeVideoWindow)
      {
       CRect r;
       deciV->getVideoDestRect(&r);
       sizeDx=r.Width();sizeDy=r.Height();
       forceChange|=oldSizeDx!=sizeDx || oldSizeDy!=sizeDy;
       oldSizeDx=sizeDx;oldSizeDy=oldSizeDy;
      }
     else
      {
       sizeDx=pict.rectFull.dx;
       sizeDy=pict.rectFull.dy;
      }

     TsubPrintPrefs printprefs(dst,stride2,dx1,dy1,deci,cfg,pict,parent->config,!!isdvdproc);
     if (!cfg->stereoscopic || isdvdproc)
      {
       printprefs.sizeDx=sizeDx;
       printprefs.sizeDy=sizeDy;
       sub->print(frameStart,wasDiscontinuity,font,forceChange,printprefs);
      }
     else
      {
       printprefs.sizeDx=sizeDx;
       printprefs.sizeDy=sizeDy/2;
       printprefs.posXpix=cfg->stereoscopic?cfg->stereoscopicPar*int(sizeDx)/2000:0;
       sub->print(frameStart,wasDiscontinuity,font,forceChange,printprefs);
       for (unsigned int i=0;i<pict.cspInfo.numPlanes;i++)
       printprefs.dst[i]+=stride2[i]*(dy1[0]/2)>>pict.cspInfo.shiftY[i];
       printprefs.posXpix=-printprefs.posXpix;
       sub->print(frameStart,false,font,false,printprefs);
      }
     wasDiscontinuity=false;
    }
   csEmbedded.Unlock();
  }

 if (cfg->cc)
  {
   csCC.Lock();
   if (cc && cc->numlines())
    {
     if (!again)
      init(pict,cfg->full,cfg->half);
     unsigned char *dst[4];
     getCurNext(FF_CSP_420P,pict,cfg->full,COPYMODE_DEF,dst);
    #if 0
     TsubtitlesSettings cfg(*cfg);
     cfg.posX=50;
     cfg.posY=100;
     cfg.align=ALIGN_CENTER;
    #else
     const TsubtitlesSettings &cfg2(*cfg);
    #endif
     TsubPrintPrefs printprefs(dst,stride2,dx1,dy1,deci,&cfg2,pict,parent->config,!!isdvdproc);
     printprefs.sizeDx=pict.rectFull.dx;
     printprefs.sizeDy=pict.rectFull.dy;

     if (memcmp(oldFontCCcfg->name,cfg2.font.name,sizeof(TfontSettingsSub)-sizeof(Toptions))!=0 || oldsplitborder!=cfg2.splitBorder)
      {
       memcpy(oldFontCCcfg,&cfg2.font,sizeof(cfg2.font));oldsplitborder=cfg2.splitBorder;
       fontCC.init(oldFontCCcfg);
      }

     cc->print(0,false,fontCC,wasCCchange,printprefs);
     wasCCchange=false;
    }
   csCC.Unlock();
  }
 return parent->deliverSample(++it,pict);
}
void TimgFilterSubtitles::onSeek(void)
{
 wasDiscontinuity=true;
 again=false;
 CAutoLock l(&csCC);
 hideClosedCaptions();
}

const char_t* TimgFilterSubtitles::getCurrentFlnm(void) const
{
 return subs.subFlnm;
}

void TimgFilterSubtitles::addClosedCaption(const char *line)
{
 CAutoLock l(&csCC);
 if (!cc)
  cc=new TsubtitleTextBase<char>(Tsubreader::SUB_SUBRIP);
 cc->add(line);
 TsubtitleFormat format(NULL);
 cc->format(format);
 wasCCchange=true;
}
void TimgFilterSubtitles::hideClosedCaptions(void)
{
 CAutoLock l(&csCC);
 if (cc)
  {
   cc->clear();
   wasCCchange=true;
  }
}

⌨️ 快捷键说明

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