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

📄 tvideocodeclibavcodec.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 "IffdshowBase.h"
#include "IffdshowDecVideo.h"
#include "IffdshowEnc.h"
#include "TvideoCodecLibavcodec.h"
#include "TglobalSettings.h"
#include "ffdshow_mediaguids.h"
#include "TcodecSettings.h"
#include "ffmpeg/libavcodec/dvdata.h"
#include "rational.h"
#include "qtpalette.h"
#include "line.h"
#include "simd.h"
#include "dsutil.h"
#include "cc_decoder.h"
#include "ffdebug.h"

TvideoCodecLibavcodec::TvideoCodecLibavcodec(IffdshowBase *Ideci,IdecVideoSink *IsinkD):
 Tcodec(Ideci),TcodecDec(Ideci,IsinkD),
 TvideoCodec(Ideci),
 TvideoCodecDec(Ideci,IsinkD),
 TvideoCodecEnc(Ideci,NULL)
{
 create();
}
TvideoCodecLibavcodec::TvideoCodecLibavcodec(IffdshowBase *Ideci,IencVideoSink *IsinkE):
 Tcodec(Ideci),TcodecDec(Ideci,NULL),
 TvideoCodec(Ideci),
 TvideoCodecDec(Ideci,NULL),
 TvideoCodecEnc(Ideci,IsinkE)
{
 create();
 if (ok && !libavcodec->dec_only)
  {
   encoders.push_back(new Tencoder(_l("MPEG-4"),CODEC_ID_MPEG4));
   encoders.push_back(new Tencoder(_l("DivX 3"),CODEC_ID_MSMPEG4V3));
   encoders.push_back(new Tencoder(_l("MS MPEG4 v2"),CODEC_ID_MSMPEG4V2));
   encoders.push_back(new Tencoder(_l("MPEG-1"),CODEC_ID_MPEG1VIDEO,Tfourccs(FOURCC_MPEG,FOURCC_MPG1,0)));
   encoders.push_back(new Tencoder(_l("MPEG-2"),CODEC_ID_MPEG2VIDEO,Tfourccs(FOURCC_MPEG,FOURCC_MPG2,0)));
   encoders.push_back(new Tencoder(_l("H.263"),CODEC_ID_H263));
   encoders.push_back(new Tencoder(_l("H.263+"),CODEC_ID_H263P));
   encoders.push_back(new Tencoder(_l("H.261"),CODEC_ID_H261));
   encoders.push_back(new Tencoder(_l("WMV 7"),CODEC_ID_WMV1));
   encoders.push_back(new Tencoder(_l("WMV 8"),CODEC_ID_WMV2));
   encoders.push_back(new Tencoder(_l("MJPEG"),CODEC_ID_MJPEG));
   encoders.push_back(new Tencoder(_l("Lossless JPEG"),CODEC_ID_LJPEG));
   encoders.push_back(new Tencoder(_l("HuffYUV"),CODEC_ID_HUFFYUV));
   encoders.push_back(new Tencoder(_l("FFV1"),CODEC_ID_FFV1));
   encoders.push_back(new Tencoder(_l("DV"),CODEC_ID_DVVIDEO));
   encoders.push_back(new Tencoder(_l("Snow (experimental)"),CODEC_ID_SNOW));
   encoders.push_back(new Tencoder(_l("FLV1"),CODEC_ID_FLV1));
  }
}
void TvideoCodecLibavcodec::create(void)
{
 ownmatrices=false;
 deci->getLibavcodec(&libavcodec);
 ok=libavcodec?libavcodec->ok:false;
 avctx=NULL;avcodec=NULL;frame=NULL;quantBytes=1;statsfile=NULL;threadcount=0;codecinited=false;extradata=NULL;theorart=false;
 ffbuf=NULL;ffbuflen=0;
 codecName[0]='\0';
 ccDecoder=NULL;
 autoSkipingLoopFilter= false;
}

TvideoCodecLibavcodec::~TvideoCodecLibavcodec()
{
 end();
 if (libavcodec) libavcodec->Release();
 if (extradata) delete extradata;
 if (ffbuf) free(ffbuf);
 if (ccDecoder) delete ccDecoder;
}
void TvideoCodecLibavcodec::end(void)
{
 if (statsfile)
  {
   fflush(statsfile);
   fclose(statsfile);
   statsfile=NULL;
  }
 if (avctx)
  {
   if (ownmatrices)
    {
     if (avctx->intra_matrix) free(avctx->intra_matrix);
     if (avctx->inter_matrix) free(avctx->inter_matrix);
     if (avctx->intra_matrix_luma) free(avctx->intra_matrix_luma);
     if (avctx->intra_matrix_chroma) free(avctx->intra_matrix_chroma);
     if (avctx->inter_matrix_luma) free(avctx->inter_matrix_luma);
     if (avctx->inter_matrix_chroma) free(avctx->inter_matrix_chroma);
     ownmatrices=false;
    }
   if (avctx->slice_offset) free(avctx->slice_offset);
   if (codecinited) libavcodec->avcodec_close(avctx);codecinited=false;
   if (threadcount) libavcodec->avcodec_thread_free(avctx);
   libavcodec->av_free(avctx);avctx=NULL;
   libavcodec->av_free(frame);frame=NULL;
  }
 avcodec=NULL;
}

//----------------------------- decompression -----------------------------
bool TvideoCodecLibavcodec::beginDecompress(TffPictBase &pict,FOURCC fcc,const CMediaType &mt,int sourceFlags)
{
 avcodec=libavcodec->avcodec_find_decoder(codecId);
 if (!avcodec) return false;

 avctx=libavcodec->avcodec_alloc_context(this);

 int numthreads=deci->getParam2(IDFF_numLAVCdecThreads);
 if (numthreads>1 && sup_threads_dec(codecId))
  libavcodec->avcodec_thread_init(avctx,threadcount=numthreads);
 else
  threadcount=0;

 frame=libavcodec->avcodec_alloc_frame();
 avctx->width =pict.rectFull.dx;
 avctx->height=pict.rectFull.dy;
 intra_matrix=avctx->intra_matrix=(uint16_t*)calloc(sizeof(uint16_t),64);
 inter_matrix=avctx->inter_matrix=(uint16_t*)calloc(sizeof(uint16_t),64);
 intra_matrix_luma=avctx->intra_matrix_luma=(uint16_t*)calloc(sizeof(uint16_t),16);
 intra_matrix_chroma=avctx->intra_matrix_chroma=(uint16_t*)calloc(sizeof(uint16_t),16);
 inter_matrix_luma=avctx->inter_matrix_luma=(uint16_t*)calloc(sizeof(uint16_t),16);
 inter_matrix_chroma=avctx->inter_matrix_chroma=(uint16_t*)calloc(sizeof(uint16_t),16);
 ownmatrices=true;

 if (deci->getParam2(IDFF_grayscale)) avctx->flags|=CODEC_FLAG_GRAY;

 avctx->codec_tag=fcc;
 avctx->workaround_bugs=deci->getParam2(IDFF_workaroundBugs);
 avctx->error_concealment=deci->getParam2(IDFF_errorConcealment);
 avctx->error_resilience=deci->getParam2(IDFF_errorResilience);
 if (sourceFlags&SOURCE_TRUNCATED || mpeg12_codec(codecId) || codecId==CODEC_ID_MJPEG)
  avctx->flags|=CODEC_FLAG_TRUNCATED;
 if (mpeg12_codec(codecId) && deci->getParam2(IDFF_fastMpeg2))
  avctx->flags2=CODEC_FLAG2_FAST;
 if (codecId==CODEC_ID_H264)
  if (int skip=deci->getParam2(IDFF_fastH264))
   avctx->skip_loop_filter=skip&2?AVDISCARD_ALL:AVDISCARD_NONREF;
 initialSkipLoopFilter= avctx->skip_loop_filter;

 avctx->debug_mv=1;//(deci->getParam2(IDFF_isVis) & deci->getParam2(IDFF_visMV));

 avctx->idct_algo=limit(deci->getParam2(IDFF_idct),0,6);
 if (extradata) delete extradata;
 extradata=new Textradata(mt,FF_INPUT_BUFFER_PADDING_SIZE);
 if (extradata->size>0 && (codecId!=CODEC_ID_H264 || fcc==FOURCC_AVC1))
  {
   avctx->extradata_size=(int)extradata->size;
   avctx->extradata=extradata->data;
   sendextradata=mpeg1_codec(codecId);
   if (fcc==FOURCC_AVC1 && mt.formattype==FORMAT_MPEG2Video)
    {
     const MPEG2VIDEOINFO *mpeg2info=(const MPEG2VIDEOINFO*)mt.pbFormat;
     avctx->nal_length_size=mpeg2info->dwFlags;
    }
   else if (fcc==FOURCC_THEO)
    {
     if (mt.formattype==FORMAT_RLTheora)
      {
       theorart=true;
       const uint8_t *src=(const uint8_t*)avctx->extradata;
       size_t dstsize=extradata->size;
       uint8_t *dst=(uint8_t*)malloc(dstsize),*dst0=dst;
       dst[1]=src[0+0*sizeof(DWORD)];
       dst[0]=src[1+0*sizeof(DWORD)];
       DWORD len0=*(DWORD*)&src[0*sizeof(DWORD)];
       memcpy(dst+2,src+16,len0);
       dst+=2+len0;

       dst[1]=src[0+1*sizeof(DWORD)];
       dst[0]=src[1+1*sizeof(DWORD)];
       DWORD len1=*(DWORD*)&src[1*sizeof(DWORD)];
       memcpy(dst+2,src+16+len0,len1);
       dst+=2+len1;

       dst[1]=src[0+2*sizeof(DWORD)];
       dst[0]=src[1+2*sizeof(DWORD)];
       DWORD len2=*(DWORD*)&src[2*sizeof(DWORD)];
       memcpy(dst+2,src+16+len0+len1,len2);

       extradata->clear();
       extradata->set(dst0,dstsize,0,true);
       free(dst0);
       avctx->extradata=extradata->data;
       avctx->extradata_size=(int)extradata->size;
      }
     if (extradata->size>2 && extradata->data[2]==0)
      {
       const uint8_t *src=(const uint8_t*)avctx->extradata;
       size_t dstsize=extradata->size;
       uint8_t *dst=(uint8_t*)malloc(dstsize);
       long len=*(long*)src;
       dst[1]=((uint8_t*)&len)[0];
       dst[0]=((uint8_t*)&len)[1];
       memcpy(dst+2,src+4,len);
       *((int16_t*)(dst+2+len))=int16_t(extradata->size-4-len);
       memcpy(dst+2+len+2,src+4+len,extradata->size-4-len);
       extradata->clear();
       extradata->set(dst,dstsize,0,true);
       free(dst);
       avctx->extradata=extradata->data;
       avctx->extradata_size=(int)extradata->size;
      }
    }
  }
 else
  sendextradata=false;
 if (fcc==FOURCC_RLE4 || fcc==FOURCC_RLE8 || fcc==FOURCC_CSCD || sup_palette(codecId))
  {
   BITMAPINFOHEADER bih;ExtractBIH(mt,&bih);
   avctx->bits_per_sample=bih.biBitCount;
   if (avctx->bits_per_sample<=8 || codecId==CODEC_ID_PNG)
    {
     avctx->palctrl=&pal;
     pal.palette_changed=1;
     const void *palette;int palettesize;
     if (!extradata->data)
      switch (avctx->bits_per_sample)
       {
        case 2:
         palette=qt_default_palette_4;
         palettesize=4*4;
         break;
        case 4:
         palette=qt_default_palette_16;
         palettesize=16*4;
         break;
        default:
        case 8:
         palette=qt_default_palette_256;
         palettesize=256*4;
         break;
       }
     else
      {
       palette=extradata->data;
       palettesize=AVPALETTE_SIZE;
      }
     memcpy(pal.palette,palette,std::min(palettesize,AVPALETTE_SIZE));
    }
  }
 else if (extradata->data && (codecId==CODEC_ID_RV10 || codecId==CODEC_ID_RV20))
  {
   #pragma pack(push, 1)
   struct rvinfo
    {
/*     DWORD dwSize, fcc1, fcc2;
     WORD w, h, bpp;
     DWORD unk1, fps, type1, type2;*/
     DWORD type1, type2;
     BYTE w2, h2, w3, h3;
    } __attribute__((packed));
   #pragma pack(pop)

   const uint8_t *src=(const uint8_t*)avctx->extradata;
   size_t dstsize=extradata->size - 26;
   uint8_t *dst=(uint8_t*)malloc(dstsize);
   memcpy(dst,src+26,dstsize);
   extradata->clear();
   extradata->set(dst,dstsize,0,true);
   free(dst);
   avctx->extradata=extradata->data;
   avctx->extradata_size=(int)extradata->size;

   rvinfo *info=(rvinfo*)extradata->data;
   avctx->sub_id=info->type2;bswap(avctx->sub_id);
  }
 if (libavcodec->avcodec_open(avctx,avcodec)<0) return false;
 pict.csp=avctx->pix_fmt!=PIX_FMT_NONE?csp_lavc2ffdshow(avctx->pix_fmt):FF_CSP_420P;
 if (avctx->sample_aspect_ratio.num && avctx->sample_aspect_ratio.den)
  pict.setSar(avctx->sample_aspect_ratio);
 containerSar=pict.rectFull.sar;
 neroavc=(sourceFlags&SOURCE_NEROAVC || avctx->codec_tag==FOURCC_MPG1 || avctx->codec_tag==FOURCC_MPG2) && avctx->codec_tag!=FOURCC_THEO;
 avgTimePerFrame=-1;
 codecinited=true;
 wasKey=false;
 segmentTimeStart=0;
 posB=1;
 return true;
}
void TvideoCodecLibavcodec::onGetBuffer(AVFrame *pic)
{
 //DPRINTF("onGetBuffer");
 pic->rtStart=rtStart;
 //rtStart=REFTIME_INVALID;
}

void TvideoCodecLibavcodec::handle_user_data(const uint8_t *buf,int buf_len)
{
 if(buf_len > 4 && *(DWORD*)buf == 0xf8014343)
  {
   if (!ccDecoder) ccDecoder=new TccDecoder(deciV);
   ccDecoder->decode(buf+2,buf_len-2);
  }
}

HRESULT TvideoCodecLibavcodec::flushDec(void)
{
 return decompress(NULL,0,NULL);
}
HRESULT TvideoCodecLibavcodec::decompress(const unsigned char *src,size_t srcLen0,IMediaSample *pIn)
{
 if (codecId==CODEC_ID_H264 || codecId==CODEC_ID_FFV1) // libavcodec can crash or loop infinitely when first frame after seeking is not keyframe
  if (!wasKey)
   if (pIn && pIn->IsSyncPoint()==S_OK)
    wasKey=true;
   else
    return pIn && pIn->IsPreroll()==S_OK?S_FALSE:S_OK;

 unsigned int skip=0;
 if (src && (codecId==CODEC_ID_RV10 || codecId==CODEC_ID_RV20) && avctx->sub_id)
  {
   avctx->slice_count=src[0]+1;
   if (!avctx->slice_offset) avctx->slice_offset=(int*)malloc(sizeof(int)*1000);
   for (int i=0;i<avctx->slice_count;i++)
    avctx->slice_offset[i]=((DWORD*)(src+1))[2*i+1];
   skip=1+2*sizeof(DWORD)*avctx->slice_count;
  }
 else if (codecId==CODEC_ID_COREPNG)
  avctx->sample_fmt=pIn && pIn->IsSyncPoint()==S_OK?SAMPLE_I:SAMPLE_P;
 else if (src && 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;
   skip+=sizeof(_TheoraPacket);
   avctx->granulepos=packet->granulepos;
  }
 src+=skip;int size=int(srcLen0-skip);
 if (pIn)
  pIn->GetTime(&rtStart,&rtStop);
 b[posB].rtStart=rtStart;b[posB].rtStop=rtStop;b[posB].srcSize=size;posB=1-posB;

 if (codecId==CODEC_ID_H264)
  {
   if(autoSkipingLoopFilter)
    {
     if(deciV->getLate()<=0)
      {
       avctx->skip_loop_filter= initialSkipLoopFilter;
       autoSkipingLoopFilter= false;
      }
    }
   else
    {
     if(deciV->shouldSkipH264loopFilter())
      {
       avctx->skip_loop_filter=AVDISCARD_ALL;
       autoSkipingLoopFilter= true;
      }
    }
  }

 while (!src || size>0)
  {
   int got_picture,used_bytes;
   avctx->parserRtStart=&rtStart;
   if (sendextradata)

⌨️ 快捷键说明

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