📄 tvideocodeclibavcodec.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 "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 + -