📄 tvideocodeclibavcodec.cpp
字号:
{
used_bytes=libavcodec->avcodec_decode_video(avctx,frame,&got_picture,extradata->data,(int)extradata->size);
sendextradata=false;
if (used_bytes>0) used_bytes=0;
}
else
{
unsigned int neededsize=size+FF_INPUT_BUFFER_PADDING_SIZE;
if (ffbuflen<neededsize)
ffbuf=(unsigned char*)realloc(ffbuf,ffbuflen=neededsize);
if (src)
{
memcpy(ffbuf,src,size);memset(ffbuf+size,0,FF_INPUT_BUFFER_PADDING_SIZE);
used_bytes=libavcodec->avcodec_decode_video(avctx,frame,&got_picture,ffbuf,size);
}
else
used_bytes=libavcodec->avcodec_decode_video(avctx,frame,&got_picture,NULL,0);
}
if (used_bytes<0)
return S_FALSE;
if (got_picture && frame->data[0])
{
int frametype;
if (avctx->codec_id==CODEC_ID_H261)
frametype=FRAME_TYPE::I;
else
switch (frame->pict_type)
{
case FF_P_TYPE:frametype=FRAME_TYPE::P;break;
case FF_B_TYPE:frametype=FRAME_TYPE::B;break;
case FF_I_TYPE:frametype=FRAME_TYPE::I;break;
case FF_S_TYPE:frametype=FRAME_TYPE::GMC;break;
case FF_SI_TYPE:frametype=FRAME_TYPE::SI;break;
case FF_SP_TYPE:frametype=FRAME_TYPE::SP;break;
case 0:frametype=pIn && pIn->IsSyncPoint()==S_OK?FRAME_TYPE::I:FRAME_TYPE::P;break;
default:frametype=FRAME_TYPE::UNKNOWN;break;
}
if (pIn && pIn->IsPreroll()==S_OK)
return sinkD->deliverPreroll(frametype);
int fieldtype=frame->interlaced_frame?(frame->top_field_first?FIELD_TYPE::INT_TFF:FIELD_TYPE::INT_BFF):FIELD_TYPE::PROGRESSIVE_FRAME;
if (frame->play_flags&CODEC_FLAG_QPEL) frametype|=FRAME_TYPE::QPEL;
int csp=csp_lavc2ffdshow(avctx->pix_fmt);
if ((avctx->flags&CODEC_FLAG_GRAY) && csp_isYUVplanar(csp)) // workaround for green picture when decoding mpeg with CODEC_FLAG_GRAY, the problem is probably somewhere else
{
if (frame->data[1][0]!=128) memset(frame->data[1],128,frame->linesize[1]*avctx->height/2);
if (frame->data[2][0]!=128) memset(frame->data[2],128,frame->linesize[2]*avctx->height/2);
}
Trect r(0,0,avctx->width,avctx->height);
if (avctx->sample_aspect_ratio.num &&
!(isMPC_matroska && avctx->sample_aspect_ratio.num==1 && avctx->sample_aspect_ratio.den==1)
) // With MPC's internal matroska splitter, AR is not reliable.
r.sar=avctx->sample_aspect_ratio;
else
r.sar=containerSar;
quants=frame->qscale_table;
quantsStride=frame->qstride;
quantType=frame->qscale_type;
h264.deblocking_filter=avctx->h264_deblocking_filter;
h264.slice_alpha_c0_offset=avctx->h264_slice_alpha_c0_offset;
h264.slice_beta_offset=avctx->h264_slice_beta_offset;
quantsDx=(r.dx+15)>>4;quantsDy=(r.dy+15)>>4;
const stride_t linesize[4]={frame->linesize[0],frame->linesize[1],frame->linesize[2],frame->linesize[3]};
TffPict pict(csp,frame->data,linesize,r,true,frametype,fieldtype,srcLen0,pIn,avctx->palctrl); //TODO: src frame size
pict.gmcWarpingPoints=frame->num_sprite_warping_points;pict.gmcWarpingPointsReal=frame->real_sprite_warping_points;
if (neroavc)
{
pict.rtStart=frame->rtStart;
if (pict.rtStart==REFTIME_INVALID)
pict.rtStart=oldpict.rtStop;
if (avgTimePerFrame==-1)
deciV->getAverageTimePerFrame(&avgTimePerFrame);
if (avgTimePerFrame)
pict.rtStop=pict.rtStart+avgTimePerFrame+frame->repeat_pict*avgTimePerFrame/2;
else
pict.rtStop=pict.rtStart+1;
if (avctx->codec_tag==FOURCC_MPG1 || avctx->codec_tag==FOURCC_MPG2)
pict.mediatimeStart=pict.mediatimeStop=REFTIME_INVALID;
oldpict=pict;
}
else if (theorart)
pict.rtStop=(pict.rtStart=frame->rtStart-segmentTimeStart)+1;
else
if (avctx->has_b_frames)
{
pict.rtStart=b[posB].rtStart;
pict.rtStop=b[posB].rtStop;
pict.srcSize=b[posB].srcSize;
}
//DPRINTF("%I64i",pict.rtStart);
HRESULT hr=sinkD->deliverDecodedSample(pict);
if (FAILED(hr) || (used_bytes && sinkD->acceptsManyFrames()!=S_OK) || avctx->codec_id==CODEC_ID_LOCO)
return hr;
}
else
if (!src)
break;
if(!used_bytes && codecId==CODEC_ID_SVQ3) return S_FALSE;
src+=used_bytes;
size-=used_bytes;
}
return S_OK;
}
bool TvideoCodecLibavcodec::onSeek(REFERENCE_TIME segmentStart)
{
wasKey=false;
segmentTimeStart=segmentStart;
posB=1;b[0].rtStart=b[1].rtStart=b[0].rtStop=b[0].rtStop=0;b[0].srcSize=b[1].srcSize=0;
return avctx?(libavcodec->avcodec_flush_buffers(avctx),true):false;
}
bool TvideoCodecLibavcodec::onDiscontinuity(void)
{
wasKey=false;
return true;
}
const char_t* TvideoCodecLibavcodec::getName(void) const
{
if (avcodec)
{
tsprintf(codecName,_l("libavcodec %s"),(const char_t*)text<char_t>(avcodec->name));
return codecName;
}
else return _l("libavcodec");
}
void TvideoCodecLibavcodec::getEncoderInfo(char_t *buf,size_t buflen) const
{
int xvid_build,divx_version,divx_build,lavc_build;
if (avctx && (mpeg12_codec(codecId) || mpeg4_codec(codecId) || x264_codec(codecId) || codecId==CODEC_ID_FLV1))
{
libavcodec->avcodec_get_encoder_info(avctx,&xvid_build,&divx_version,&divx_build,&lavc_build);
if (xvid_build)
tsnprintf(buf,buflen,_l("XviD build %i"),xvid_build);
else if (lavc_build)
tsnprintf(buf,buflen,_l("libavcodec build %i"),lavc_build);
else if (divx_version || divx_build)
tsnprintf(buf,buflen,_l("DivX version %i.%02i, build %i"),divx_version/100,divx_version%100,divx_build);
else
strncpy(buf,_l("unknown"),buflen);
}
else
strncpy(buf,_l("unknown"),buflen);
buf[buflen-1]='\0';
}
void TvideoCodecLibavcodec::line(unsigned char *dst,unsigned int _x0,unsigned int _y0,unsigned int _x1,unsigned int _y1,stride_t strideY)
{
drawline< TaddColor<100> >(_x0,_y0,_x1,_y1,100,dst,strideY);
}
void TvideoCodecLibavcodec::draw_arrow(uint8_t *buf, int sx, int sy, int ex, int ey, stride_t stride,int mulx,int muly,int dstdx,int dstdy)
{
sx=limit(mulx*sx>>12,0,dstdx-1);sy=limit(muly*sy>>12,0,dstdy-1);
ex=limit(mulx*ex>>12,0,dstdx-1);ey=limit(muly*ey>>12,0,dstdy-1);
int dx,dy;
dx= ex - sx;
dy= ey - sy;
if(dx*dx + dy*dy > 3*3){
int rx= dx + dy;
int ry= -dx + dy;
int length= ff_sqrt((rx*rx + ry*ry)<<8);
//FIXME subpixel accuracy
rx= roundDiv(rx*3<<4, length);
ry= roundDiv(ry*3<<4, length);
line(buf, sx, sy, sx + rx, sy + ry, stride);
line(buf, sx, sy, sx - ry, sy + rx, stride);
}
line(buf, sx, sy, ex, ey, stride);
}
bool TvideoCodecLibavcodec::drawMV(unsigned char *dst,unsigned int dstdx,stride_t stride,unsigned int dstdy) const
{
if (!frame->motion_val || !frame->mb_type || !frame->motion_val[0]) return false;
#define IS_8X8(a) ((a)&MB_TYPE_8x8)
#define IS_16X8(a) ((a)&MB_TYPE_16x8)
#define IS_8X16(a) ((a)&MB_TYPE_8x16)
#define IS_INTERLACED(a) ((a)&MB_TYPE_INTERLACED)
#define USES_LIST(a, list) ((a) & ((MB_TYPE_P0L0|MB_TYPE_P1L0)<<(2*(list))))
const int shift= 1 + ((frame->play_flags&CODEC_FLAG_QPEL)?1:0);
const int mv_sample_log2= 4 - frame->motion_subsample_log2;
const int mv_stride= (frame->mb_width << mv_sample_log2) + (avctx->codec_id == CODEC_ID_H264 ? 0 : 1);
int direction=0;
int mulx=(dstdx<<12)/avctx->width;
int muly=(dstdy<<12)/avctx->height;
for(int mb_y=0; mb_y<frame->mb_height; mb_y++)
for(int mb_x=0; mb_x<frame->mb_width; mb_x++)
{
const int mb_index= mb_x + mb_y*frame->mb_stride;
if (!USES_LIST(frame->mb_type[mb_index], direction))
continue;
if(IS_8X8(frame->mb_type[mb_index]))
for(int i=0; i<4; i++)
{
int sx= mb_x*16 + 4 + 8*(i&1) ;
int sy= mb_y*16 + 4 + 8*(i>>1);
int xy= (mb_x*2 + (i&1) + (mb_y*2 + (i>>1))*mv_stride)<<(mv_sample_log2-1);
int mx= (frame->motion_val[direction][xy][0]>>shift) + sx;
int my= (frame->motion_val[direction][xy][1]>>shift) + sy;
draw_arrow(dst,sx,sy,mx,my,stride,mulx,muly,dstdx,dstdy);
}
else if(IS_16X8(frame->mb_type[mb_index]))
for(int i=0; i<2; i++)
{
int sx=mb_x*16 + 8;
int sy=mb_y*16 + 4 + 8*i;
int xy=(mb_x*2 + (mb_y*2 + i)*mv_stride) << (mv_sample_log2-1);
int mx=frame->motion_val[direction][xy][0]>>shift;
int my=frame->motion_val[direction][xy][1]>>shift;
if (IS_INTERLACED(frame->mb_type[mb_index]))
my*=2;
draw_arrow(dst,sx,sy,mx+sx,my+sy,stride,mulx,muly,dstdx,dstdy);
}
else if(IS_8X16(frame->mb_type[mb_index]))
for(int i=0; i<2; i++)
{
int sx=mb_x*16 + 4 + 8*i;
int sy=mb_y*16 + 8;
int xy= (mb_x*2 + i + mb_y*2*mv_stride) << (mv_sample_log2-1);
int mx=(frame->motion_val[direction][xy][0]>>shift);
int my=(frame->motion_val[direction][xy][1]>>shift);
if(IS_INTERLACED(frame->mb_type[mb_index]))
my*=2;
draw_arrow(dst,sx,sy,mx+sx,my+sy,stride,mulx,muly,dstdx,dstdy);
}
else
{
int sx= mb_x*16 + 8;
int sy= mb_y*16 + 8;
int xy= (mb_x + mb_y*mv_stride) << mv_sample_log2;
int mx= (frame->motion_val[direction][xy][0]>>shift) + sx;
int my= (frame->motion_val[direction][xy][1]>>shift) + sy;
draw_arrow(dst,sx,sy,mx,my,stride,mulx,muly,dstdx,dstdy);
}
}
#undef IS_8X8
#undef IS_16X8
#undef IS_8X16
#undef IS_INTERLACED
#undef USES_LIST
return true;
}
//------------------------------ compression ------------------------------
void TvideoCodecLibavcodec::getCompressColorspaces(Tcsps &csps,unsigned int outDx,unsigned int outDy)
{
switch (coCfg->codecId)
{
case CODEC_ID_HUFFYUV:
if (coCfg->huffyuv_csp==0)
csps.add(FF_CSP_422P);
else
csps.add(FF_CSP_420P);
break;
case CODEC_ID_FFV1:
switch (coCfg->ffv1_csp)
{
case FOURCC_YV12:csps.add(FF_CSP_420P);break;
case FOURCC_444P:csps.add(FF_CSP_444P);break;
case FOURCC_422P:csps.add(FF_CSP_422P);break;
case FOURCC_411P:csps.add(FF_CSP_411P);break;
case FOURCC_410P:csps.add(FF_CSP_410P);break;
case FOURCC_RGB3:csps.add(FF_CSP_RGB32);break;
}
break;
case CODEC_ID_MJPEG:
csps.add(FF_CSP_420P|FF_CSP_FLAGS_YUV_JPEG);
break;
case CODEC_ID_LJPEG:
if (coCfg->ljpeg_csp==FOURCC_RGB3)
csps.add(FF_CSP_RGB32);
else
csps.add(FF_CSP_420P);
break;
case CODEC_ID_DVVIDEO:
{
std::vector<const DVprofile*> profiles=coCfg->getDVprofile(outDx,outDy);
if (!profiles.empty())
{
for (std::vector<const DVprofile*>::const_iterator p=profiles.begin();p!=profiles.end();p++)
csps.add(csp_lavc2ffdshow((*p)->pix_fmt));
}
else
csps.add(FF_CSP_420P); //won't be used anyway
break;
}
case CODEC_ID_SVQ1:
csps.add(FF_CSP_410P);
break;
default:
csps.add(FF_CSP_420P);
break;
}
}
bool TvideoCodecLibavcodec::supExtradata(void)
{
return coCfg->codecId==CODEC_ID_HUFFYUV || (sup_globalheader(coCfg->codecId) && coCfg->globalHeader);
}
bool TvideoCodecLibavcodec::getExtradata(const void* *ptr,size_t *len)
{
if (!avctx || !len) return false;
*len=avctx->extradata_size;
if (ptr) *ptr=avctx->extradata;
return true;
}
LRESULT TvideoCodecLibavcodec::beginCompress(int cfgcomode,int csp,const Trect &r)
{
_mm_empty();
avctx=libavcodec->avcodec_alloc_context();
frame=libavcodec->avcodec_alloc_frame();
avcodec=libavcodec->avcodec_find_encoder((CodecID)coCfg->codecId);
if (!avcodec) return ICERR_ERROR;
this->cfgcomode=cfgcomode;
if (coCfg->numthreads>1 && sup_threads(coCfg->codecId))
libavcodec->avcodec_thread_init(avctx,threadcount=coCfg->numthreads);
else
threadcount=0;
avctx->width=r.dx;avctx->height=r.dy;
mb_width =(avctx->width+15)/16;
mb_height=(avctx->height+15)/16;
mb_count=mb_width*mb_height;
avctx->time_base.den=deci->getParam2(IDFF_enc_fpsRate);
avctx->time_base.num=deci->getParam2(IDFF_enc_fpsScale);
if (avctx->time_base.den>(1<<16)-1)
{
avctx->time_base.num=(int)(0.5+(double)avctx->time_base.num/avctx->time_base.den*((1<<16)-1));
avctx->time_base.den=(1<<16)-1;
}
if (coCfg->codecId==CODEC_ID_FFV1)
avctx->gop_size=coCfg->ffv1_key_interval;
else
avctx->gop_size=coCfg->max_key_interval;
avctx->codec_tag=coCfg->fourcc;
if (sup_interlace(coCfg->codecId) && coCfg->interlacing) avctx->flags|=CODEC_FLAG_INTERLACED_DCT|CODEC_FLAG_INTERLACED_ME;
if (sup_globalheader(coCfg->codecId) && coCfg->globalHeader) avctx->flags|=CODEC_FLAG_GLOBAL_HEADER;
if (sup_part(coCfg->codecId) &&coCfg->part) avctx->flags|=CODEC_FLAG_PART;
if (coCfg->codecId!=CODEC_ID_SNOW && coCfg->codecId!=CODEC_ID_H261) avctx->mb_decision=coCfg->me_hq;
if (coCfg->me_4mv && sup_4mv(coCfg->codecId)) avctx->flags|=CODEC_FLAG_4MV;
if (sup_qpel(coCfg->codecId) && coCfg->me_qpel)
{
avctx->flags|=CODEC_FLAG_QPEL;
avctx->me_subpel_quality=coCfg->me_subq;
}
psnr=deci->getParam2(IDFF_enc_psnr);if (psnr) avctx->flags|=CODEC_FLAG_PSNR;
if (coCfg->me_mv0 && sup_me_mv0(coCfg->codecId) && coCfg->me_hq>0) avctx->flags|=CODEC_FLAG_MV0;
avctx->me_cmp=coCfg->me_cmp;if (coCfg->me_cmp_chroma && !coCfg->gray) avctx->me_cmp|=FF_CMP_CHROMA;
avctx->me_sub_cmp=coCfg->me_subcmp;if (coCfg->me_subcmp_chroma && !coCfg->gray) avctx->me_sub_cmp|=FF_CMP_CHROMA;
avctx->mb_cmp=coCfg->mb_cmp;if (coCfg->mb_cmp_chroma && !coCfg->gray) avctx->mb_cmp|=FF_CMP_CHROMA;
avctx->dia_size=Tlibavcodec::dia_sizes[coCfg->dia_size].size;
avctx->last_predictor_count=coCfg->me_last_predictor_count;
avctx->pre_me=coCfg->me_prepass;
avctx->me_pre_cmp=coCfg->me_precmp;if (coCfg->me_precmp_chroma && !coCfg->gray) avctx->me_pre_cmp|=FF_CMP_CHROMA;
avctx->pre_dia_size=Tlibavcodec::dia_sizes[coCfg->dia_size_pre].size;
avctx->nsse_weight=coCfg->me_nsse_weight;
if (sup_gray(coCfg->codecId) && coCfg->gray) avctx->flags|=CODEC_FLAG_GRAY;
if (coCfg->isQuantControlActive())
{
avctx->qmin_i=coCfg->limitq(coCfg->q_i_min);avctx->qmax_i=coCfg->limitq(coCfg->q_i_max);
avctx->qmin =coCfg->limitq(coCfg->q_p_min);avctx->qmax =coCfg->limitq(coCfg->q_p_max);
avctx->qmin_b=coCfg->limitq(coCfg->q_b_min);avctx->qmax_b=coCfg->limitq(coCfg->q_b_max);
}
else
{
avctx->qmin_i=avctx->qmin=avctx->qmin_b=coCfg->getMinMaxQuant().first;
avctx->qmax_i=avctx->qmax=avctx->qmax_b=coCfg->getMinMaxQuant().second;
}
if (coCfg->codecId!=CODEC_ID_MJPEG)
{
avctx->i_quant_factor=coCfg->i_quant_factor/100.0f;
avctx->i_quant_offset=coCfg->i_quant_offset/100.0f;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -