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

📄 tvideocodectheora.cpp

📁 从FFMPEG转换而来的H264解码程序,VC下编译..
💻 CPP
字号:
/*
 * 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 "Tdll.h"
#include "TvideoCodecTheora.h"
#include "IffdshowBase.h"
#include "IffdshowEnc.h"
#include "TcodecSettings.h"
#include "simd.h"
#include "ffdebug.h"
#include "dsutil.h"
#include "theora/cpu.h"
#include "ffdshow_mediaguids.h"

const char_t* TvideoCodecTheora::dllname=_l("ff_theora.dll");

TvideoCodecTheora::TvideoCodecTheora(IffdshowBase *Ideci,IdecVideoSink *IsinkD):
 Tcodec(Ideci),TcodecDec(Ideci,IsinkD),
 TvideoCodecDec(Ideci,IsinkD),
 TvideoCodecEnc(Ideci,NULL),
 TvideoCodec(Ideci)
{
 create();
}
TvideoCodecTheora::TvideoCodecTheora(IffdshowBase *Ideci,IencVideoSink *IsinkE):
 Tcodec(Ideci),TcodecDec(Ideci,NULL),
 TvideoCodecDec(Ideci,NULL),
 TvideoCodecEnc(Ideci,IsinkE),
 TvideoCodec(Ideci)
{
 create();
 if (ok)
  encoders.push_back(new Tencoder(_l("Theora"),CODEC_ID_THEORA_LIB));
}

void TvideoCodecTheora::create(void)
{
 dll=new Tdll(dllname,config);
 dll->loadFunction(theora_info_init,"theora_info_init");
 dll->loadFunction(theora_comment_init,"theora_comment_init");
 dll->loadFunction(theora_decode_init,"theora_decode_init");
 dll->loadFunction(theora_decode_header,"theora_decode_header");
 dll->loadFunction(theora_decode_packetin,"theora_decode_packetin");
 dll->loadFunction(theora_decode_YUVout,"theora_decode_YUVout");
 dll->loadFunction(theora_encode_init,"theora_encode_init");
 dll->loadFunction(theora_encode_header,"theora_encode_header");
 dll->loadFunction(theora_encode_YUVin,"theora_encode_YUVin");
 dll->loadFunction(theora_encode_packetout,"theora_encode_packetout");
 dll->loadFunction(theora_clear,"theora_clear");
 dll->loadFunction(theora_info_clear,"theora_info_clear");
 dll->loadFunction(theora_comment_clear,"theora_comment_clear");
 dll->loadFunction(theora_encode_comment,"theora_encode_comment");
 dll->loadFunction(theora_encode_tables,"theora_encode_tables");
 dll->loadFunction(theora_granule_frame,"theora_granule_frame");
 dll->loadFunction(set_cpu_flags,"set_cpu_flags");
 ok=dll->ok;
 if (ok)
  {
   int cpu=0;
   if (Tconfig::cpu_flags&FF_CPU_MMX   ) cpu|=CPU_X86_MMX;
   if (Tconfig::cpu_flags&FF_CPU_3DNOW ) cpu|=CPU_X86_3DNOW;
   if (Tconfig::cpu_flags&FF_CPU_MMXEXT) cpu|=CPU_X86_MMXEXT;
   if (Tconfig::cpu_flags&FF_CPU_SSE   ) cpu|=CPU_X86_SSE;
   if (Tconfig::cpu_flags&FF_CPU_SSE2  ) cpu|=CPU_X86_SSE2;
   set_cpu_flags(cpu);
  }
 memset(&td,0,sizeof(td));memset(&ti,0,sizeof(ti));memset(&tc,0,sizeof(tc));
 inited=false;
 extradata=NULL;
 segmentTimeStart=0;
}
TvideoCodecTheora::~TvideoCodecTheora()
{
 end();
 if (dll) delete dll;
}
void TvideoCodecTheora::end(void)
{
 if (inited)
  {
   theora_clear(&td);
   theora_info_clear(&ti);// memset(&td,0,sizeof(td));
   tc.vendor=NULL;
   theora_comment_clear(&tc);//memset(&ti,0,sizeof(ti));
   inited=false;
  }
 if (extradata) free(extradata);extradata=NULL;
}

bool TvideoCodecTheora::beginDecompress(TffPictBase &pict,FOURCC infcc,const CMediaType &mt,int sourceFlags)
{
 inited=false;theorart=false;
 memset(&ill,0,sizeof(ill));
 if (mt.formattype==FORMAT_RLTheora)
  {
   theorart=true;
  }
 else if (mt.formattype==FORMAT_TheoraIll)
  {
   ill=*(const sTheoraFormatBlock*)mt.Format();
   lastSeenStartGranPos=0;
   frameDuration=(UNITS*ill.frameRateDenominator)/ill.frameRateNumerator;
   frameCount=0;
  }
 rd=pict.rectFull;
 pict.csp=FF_CSP_420P;
 Textradata extradata(mt);
 if (extradata.data && extradata.size>2)
  {
   if (theorart)
    {
     theora_info_init(&ti);
     theora_comment_init(&tc);
     const uint8_t *src=extradata.data;

     ogg_packet op;memset(&op,0,sizeof(op));
     op.b_o_s=1;

     op.packet=(unsigned char*)src+16;
     DWORD len0=*(DWORD*)&src[0*sizeof(DWORD)];
     op.bytes=len0;
     if (theora_decode_header(&ti,&tc,&op)!=0)
      return false;

     op.packet=(unsigned char*)src+16+len0;
     DWORD len1=*(DWORD*)&src[1*sizeof(DWORD)];
     op.bytes=len1;
     if (theora_decode_header(&ti,&tc,&op)!=0)
      return false;

     op.packet=(unsigned char*)src+16+len0+len1;
     DWORD len2=*(DWORD*)&src[2*sizeof(DWORD)];
     op.bytes=len2;
     if (theora_decode_header(&ti,&tc,&op)!=0)
      return false;
    }
   else if (extradata.data[2]==0)
    {
     theora_info_init(&ti);
     ti.width=rd.dx;
     ti.height=rd.dy;
     ti.fps_numerator=25;
     ti.fps_denominator=1;
     ti.aspect_numerator=1;
     ti.aspect_denominator=1;
     ti.version_major=3;
     theora_comment_init(&tc);tc.vendor="ff_theora";
     ogg_packet op;memset(&op,0,sizeof(op));
     op.packet=(unsigned char*)extradata.data;
     op.bytes=(long)extradata.size;
     op.b_o_s=1;
     long len=*(long*)op.packet;op.packet+=4;op.bytes-=4;
     if (theora_decode_header(&ti,&tc,&op)!=0)
      return false;
    }
   else
    {
     const unsigned char *ptr=extradata.data;
     theora_info_init(&ti);
     theora_comment_init(&tc);
     while (ptr<extradata.data+extradata.size)
      {
       int16_t size=*(int16_t*)ptr;ptr+=sizeof(int16_t);
       bswap(size);
       ogg_packet op;memset(&op,0,sizeof(op));
       op.packet=(unsigned char*)ptr;
       op.bytes=size;
       op.b_o_s=1;
       if (theora_decode_header(&ti,&tc,&op)!=0)
        return false;
       ptr+=size;
      }
    }
   ti.postprocessingLevel=deci->getParam2(IDFF_libtheoraPostproc)?6:0;
   if (theora_decode_init(&td,&ti)==0)
    return inited=true;
   else
    return false;
  }
 else
  {
   theora_info_init(&ti);
   theora_comment_init(&tc);
   return true;
  }
}
HRESULT TvideoCodecTheora::decompress(const unsigned char *src,size_t srcLen,IMediaSample *pIn)
{
 ogg_packet op;memset(&op,0,sizeof(op));
 if (theorart)
  {
   struct _TheoraPacket
    {
     long  bytes;
     long  b_o_s;
     long  e_o_s;
     int64_t  granulepos;
     int64_t  packetno;
    };
   _TheoraPacket *packet=(_TheoraPacket*)src;
   if (packet->bytes==0 || src[sizeof(_TheoraPacket)]&0x80)
    return S_OK;
   src+=sizeof(_TheoraPacket);srcLen-=sizeof(_TheoraPacket);
   op.granulepos=packet->granulepos;
  }

 if (ill.width)
  {
   REFERENCE_TIME rtStart=0,rtStop=0;
   pIn->GetTime(&rtStart,&rtStop);
   if (rtStart!=-1 && rtStart!=lastSeenStartGranPos)
    lastSeenStartGranPos=rtStart;
  }

 op.packet=(unsigned char*)src;
 op.bytes=(long)srcLen;
 if (op.packet[0]&0x80)
  {
   op.b_o_s=1;
   inited=false;
   int ret=theora_decode_header(&ti,&tc,&op);
   return S_FALSE;
  }

 if (!inited)
  {
   ti.postprocessingLevel=deci->getParam2(IDFF_libtheoraPostproc)?6:0;
   int ret=theora_decode_init(&td,&ti);
   if (ret==0) inited=true;
  }

 if (!inited) return S_FALSE;
 theora_decode_packetin(&td,&op);
 yuv_buffer yuv;memset(&yuv,0,sizeof(yuv));
 int ret=theora_decode_YUVout(&td,&yuv);
 _mm_empty();
 if (ret==0)
  {
   if (pIn->IsPreroll()==S_OK)
    return sinkD->deliverPreroll(yuv.keyframe?FRAME_TYPE::I:FRAME_TYPE::P);
   unsigned char *data[4]={(unsigned char*)yuv.y,(unsigned char*)yuv.u,(unsigned char*)yuv.v,NULL};
   stride_t stride[4]={yuv.y_stride,yuv.uv_stride,yuv.uv_stride,0};
   if (ti.aspect_numerator)
    rd.sar=Rational((int)ti.aspect_numerator,(int)ti.aspect_denominator);
   TffPict pict(FF_CSP_420P,data,stride,rd,true,yuv.keyframe?FRAME_TYPE::I:FRAME_TYPE::P,FIELD_TYPE::PROGRESSIVE_FRAME,srcLen,pIn);
   if (ill.width)
    {
     unsigned long locMod=1<<ill.maxKeyframeInterval;
     unsigned long locInterFrameNo=(unsigned int)(lastSeenStartGranPos%locMod);
     LONGLONG locAbsFramePos=((lastSeenStartGranPos>>ill.maxKeyframeInterval))+locInterFrameNo;
     REFERENCE_TIME locTimeBase=locAbsFramePos*frameDuration/*-mSeekTimeBase*/;
     REFERENCE_TIME locFrameStart=locTimeBase+frameCount*frameDuration;
     frameCount++;
     REFERENCE_TIME locFrameEnd=locTimeBase+frameCount*frameDuration;
     pict.rtStart=locFrameStart;
     pict.rtStop=locFrameEnd;
     pict.mediatimeStart=pict.mediatimeStop=REFTIME_INVALID;
    }
   else if (theorart)
    {
     pict.rtStart=ti.fps_denominator*REF_SECOND_MULT*theora_granule_frame(&td,td.granulepos)/ti.fps_numerator;
     pict.rtStart=pict.rtStart-segmentTimeStart;
     pict.rtStop=pict.rtStart+1;
     pict.mediatimeStart=pict.mediatimeStop=REFTIME_INVALID;
    }
   return sinkD->deliverDecodedSample(pict);
  }
 else
  return S_FALSE;
}

LRESULT TvideoCodecTheora::beginCompress(int cfgcomode,int csp,const Trect &r)
{
 this->cfgcomode=cfgcomode;
 theora_info_init(&ti);
 ti.width=ti.frame_width=r.dx;
 ti.height=ti.frame_height=r.dy;
 ti.fps_numerator=deci->getParam2(IDFF_enc_fpsRate);
 ti.fps_denominator=deci->getParam2(IDFF_enc_fpsScale);
 Rational sar=coCfg->sar(r.dx,r.dy).reduce(10000);
 ti.aspect_numerator=sar.num;
 ti.aspect_denominator=sar.den;
 ti.sharpness=coCfg->theo_sharpness;
 ti.noise_sensitivity=coCfg->theo_noisesensitivity;
 ti.dropframes_p=coCfg->dropFrames;
 ti.quick_p=coCfg->theo_hq?0:1;
 ti.keyframe_auto_p=1;
 ti.keyframe_frequency=coCfg->max_key_interval;
 ti.keyframe_frequency_force=coCfg->max_key_interval;
 ti.keyframe_auto_threshold=coCfg->keySceneChange;
 ti.keyframe_mindistance=coCfg->min_key_interval;

 switch (cfgcomode)
  {
   case ENC_MODE::UNKNOWN:
   case ENC_MODE::CBR:
    ti.target_bitrate=coCfg->bitrate1000*1000;
    ti.keyframe_data_target_bitrate=ogg_uint32_t(ti.target_bitrate*1.5);
    ti.quality=0;
    break;
   case ENC_MODE::VBR_QUAL:
   case ENC_MODE::VBR_QUANT:
   case ENC_MODE::PASS2_1:
   case ENC_MODE::PASS2_2_INT:
   case ENC_MODE::PASS2_2_EXT:
    ti.quality=63*coCfg->qual/100;
    ti.target_bitrate=0;ti.keyframe_data_target_bitrate=0;
    break;
   default:
    return ICERR_ERROR;
  }
 if (theora_encode_init(&td,&ti)==0)
  {
   inited=true;
   firstframe=true;
   ogg_packet op;
   TbyteBuffer buf;
   int16_t sizeb;
   theora_encode_header(&td,&op);deciE->muxHeader(&op,0,false);buf.append(bswap(sizeb=(int16_t)op.bytes));buf.append(op.packet,op.bytes);
   theora_comment_init(&tc);
   theora_encode_comment(&tc,&op);deciE->muxHeader(&op,0,false);buf.append(bswap(sizeb=(int16_t)op.bytes));buf.append(op.packet,op.bytes);
   theora_encode_tables(&td,&op);deciE->muxHeader(&op,0,true);buf.append(bswap(sizeb=(int16_t)op.bytes));buf.append(op.packet,op.bytes);
   if (extradata) free(extradata);
   extradatalen=buf.size();
   extradata=(unsigned char*)malloc(buf.size());
   memcpy(extradata,&buf[0],buf.size());
   return ICERR_OK;
  }
 else
  return ICERR_ERROR;
}

bool TvideoCodecTheora::getExtradata(const void* *ptr,size_t *len)
{
 if (!inited || !len) return false;
 *len=extradatalen;
 if (ptr) *ptr=extradata;
 return true;
}

HRESULT TvideoCodecTheora::compress(const TffPict &pict,TencFrameParams &params)
{
 yuv_buffer yuv;
 yuv.y_width =ti.width      ;yuv.uv_width =yuv.y_width /2;
 yuv.y_stride=(int)pict.stride[0];yuv.uv_stride=(int)pict.stride[1];
 yuv.y_height=ti.height     ;yuv.uv_height=yuv.y_height/2;

 yuv.y=pict.data[0];
 yuv.u=pict.data[1];
 yuv.v=pict.data[2];

 int fixedq=(params.quant!=-1)?int(63-63*pow(double(coCfg->limitq(params.quant)-1),0.2)/pow(29.0,0.2)+0.5):-1; //no math here, just have tried few values
 int keyframe;
 int res=theora_encode_YUVin(&td,&yuv,&fixedq,&keyframe);
 if (res<0)
  {
   params.frametype=FRAME_TYPE::DELAY;
   params.length=0;
   return sinkE->deliverError();
  }

 if (theora_encode_packetout(&td,0,&openc)==0)
  return sinkE->deliverError();
 else
  {
   TmediaSample sample;
   HRESULT hr;
   if (FAILED(hr=sinkE->getDstBuffer(&sample,pict)))
    return hr;
   memcpy(sample,openc.packet,openc.bytes);params.length=openc.bytes;
   params.priv=&openc;
   params.frametype=keyframe?(params.keyframe=true,FRAME_TYPE::I):FRAME_TYPE::P;
   if (params.quant==-1) params.quant=30*(63-fixedq)/63+1;

   return sinkE->deliverEncodedSample(sample,params);
  }
}

bool TvideoCodecTheora::onSeek(REFERENCE_TIME segmentStart)
{
 segmentTimeStart=segmentStart;
 return true;
}

⌨️ 快捷键说明

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