📄 umc_mpeg2_enc.cpp
字号:
bExtendGOP = false;
for (ntry=0; ; ntry++) {
// Save position after headers (only 0th thread)
Ipp32s DisplayFrameNumber;
PrepareBuffers();
size = 0;
// Mpeg2 sequence header
if (m_FirstFrame || (picture_coding_type == I_PICTURE)) {
PutSequenceHeader();
PutSequenceExt();
PutSequenceDisplayExt(); // no need
// optionally output some text data
PutUserData(0);
PutGOPHeader(encodeInfo.numEncodedFrames);
size = (32+7 + BITPOS(threadSpec[0]))>>3;
}
PictureRateControl(size*8+32);
DisplayFrameNumber = encodeInfo.numEncodedFrames;
if (picture_coding_type == B_PICTURE)
DisplayFrameNumber--;
else if(!closed_gop) // closed can be only while I is encoded
DisplayFrameNumber += num_btype;
temporal_reference = DisplayFrameNumber - m_GOP_Start;
if(picture_coding_type == I_PICTURE) {
if(quantiser_scale_value < 5)
encodeInfo.intraVLCFormat[picture_coding_type - I_PICTURE] = 1;
else if(quantiser_scale_value > 15)
encodeInfo.intraVLCFormat[picture_coding_type - I_PICTURE] = 0;
curr_intra_vlc_format = encodeInfo.intraVLCFormat[picture_coding_type - I_PICTURE];
}
PutPictureHeader();
PutPictureCodingExt();
PutUserData(2);
if (encodeInfo.numThreads > 1) {
// start additional thread(s)
for (i = 0; i < encodeInfo.numThreads - 1; i++) {
vm_event_signal(&threads[i]->start_event);
}
}
switch (picture_coding_type) {
case I_PICTURE:
encodeI(0);
break;
case P_PICTURE:
encodeP(0);
break;
case B_PICTURE:
encodeB(0);
break;
}
if (encodeInfo.numThreads > 1) {
// wait additional thread(s)
for (i = 0; i < encodeInfo.numThreads - 1; i++) {
vm_event_wait(&threads[i]->stop_event);
}
}
// flush buffer
status = UMC_OK;
p = out_pointer;
Ipp32s fieldCount = 0;
// move encoded data from all threads to first
for (i = 0; i < encodeInfo.numThreads; i++) {
// align to byte border (not word)
FLUSH_BITSTREAM(threadSpec[i].bBuf.current_pointer, threadSpec[i].bBuf.bit_offset);
size = BITPOS(threadSpec[i])>>3;
fieldCount += threadSpec[i].fieldCount;
if (size > thread_buffer_size) {
status = UMC_ERR_NOT_ENOUGH_BUFFER;
break;
}
if (i) {
memcpy(p, threadSpec[i].bBuf.start_pointer, size);
}
p += size;
}
if(!curr_frame_dct)
encodeInfo.altscan_tab[picture_coding_type-I_PICTURE] =
(fieldCount > 0) ? 1 : 0;
// align encoded size to 4
while ((size_t)p & 3) *p++ = 0;
// summary size
size = (Ipp32s)(p - out_pointer);
isfield = (picture_structure != FRAME_PICTURE);
bitsize = size*8;
if(encodeInfo.rc_mode == RC_CBR) {
target_size = rc_tagsize[picture_coding_type-I_PICTURE];
wanted_size = (Ipp32s)(target_size - rc_dev / 3 * target_size / rc_tagsize[0]);
wanted_size >>= isfield;
} else {
target_size = wanted_size = bitsize; // no estimations
}
if(picture_coding_type == I_PICTURE) {
if(bitsize > (MBcount*128>>isfield))
encodeInfo.intraVLCFormat[0] = 1;
else //if(bitsize < MBcount*192)
encodeInfo.intraVLCFormat[0] = 0;
}
#ifdef SCENE_DETECTION
bSceneChanged = false;
if ( picture_coding_type == P_PICTURE && second_field == 0 && bExtendGOP == false) { //
Ipp32s numIntra = 0;
Ipp32s t;
for (t = 0; t < encodeInfo.numThreads; t++) {
numIntra += threadSpec[t].numIntra;
}
if(picture_structure != FRAME_PICTURE)
numIntra <<= 1; // MBcount for the frame picture
if (numIntra*2 > MBcount*1 // 1/2 Intra: I frame instead of P
) {
picture_coding_type = I_PICTURE;
curr_gop = 0;
bSceneChanged = true;
mp_f_code = 0;
m_GOP_Start_tmp = m_GOP_Start;
m_GOP_Start = encodeInfo.numEncodedFrames;
ntry = -1;
continue;
}
}
// scene change not detected
#endif
oldq = prevq;
prevq = quantiser_scale_value;
bQuantiserChanged = false;
if (status == UMC_ERR_NOT_ENOUGH_BUFFER || bitsize > rc_vbv_max
|| (bitsize > wanted_size*2 && (ntry==0 || oldq<prevq)) )
{
changeQuant(quantiser_scale_value + 1);
if(prevq == quantiser_scale_value) {
if (picture_coding_type == I_PICTURE && !m_FirstFrame &&
(status == UMC_ERR_NOT_ENOUGH_BUFFER || bitsize > rc_vbv_max)) {
picture_coding_type = P_PICTURE;
m_GOP_Start = m_GOP_Start_tmp;
mp_f_code = pMotionData[0].f_code;
bExtendGOP = true;
curr_gop += encodeInfo.IPDistance;
ntry = -1;
continue;
}
status = UMC_ERR_FAILED; // already maximum;
} else {
bQuantiserChanged = true;
continue;
}
} else if (bitsize < rc_vbv_min )
{
if(ntry==0 || oldq>prevq)
changeQuant(quantiser_scale_value - 1);
if(prevq == quantiser_scale_value) {
while(bitsize < rc_vbv_min) {
*(Ipp32u*)p = 0;
p += 4;
size += 4;
bitsize += 32;
}
status = UMC_OK; // already minimum;
} else {
bQuantiserChanged = true;
continue;
}
}
// if (!bQuantiserChanged && !bSceneChanged)
m_FirstFrame = 0;
qscale[picture_coding_type-I_PICTURE] = quantiser_scale_value;
out_pointer += size;
output_buffer_size -= size;
mEncodedSize += size;
PostPictureRateControl(size*8);
return status;
}
}
// Initializes internal frame so that it has original dimension but uses
// buffer with aligned dimension
void MPEG2VideoEncoderBase::InitInternalFrame(VideoData* frame)
{
frame->SetAlignment(16);
frame->Init(encodeInfo.info.clip_info.width, encodeInfo.info.clip_info.height, encodeInfo.info.color_format, 8);
frame->SetPlanePitch(YFrameHSize, 0);
frame->SetPlanePitch(UVFrameHSize, 1);
frame->SetPlanePitch(UVFrameHSize, 2);
frame->SetTime(-1);
}
// Initializes internal frame so that it has original dimension but uses
// buffer with aligned dimension.
// The length of the buffer must be YUVFrameSize.
void MPEG2VideoEncoderBase::SetInternalFramePointers(VideoData* frame, Ipp8u* buffer)
{
frame->SetPlanePointer(buffer, 0); buffer += YFrameSize;
frame->SetPlanePointer(buffer, 1); buffer += UVFrameSize;
frame->SetPlanePointer(buffer, 2);
}
const Ipp32s sorted_ratio[][2] = {
{1,32},{1,31},{1,30},{1,29},{1,28},{1,27},{1,26},{1,25},{1,24},{1,23},{1,22},{1,21},{1,20},{1,19},{1,18},{1,17},
{1,16},{2,31},{1,15},{2,29},{1,14},{2,27},{1,13},{2,25},{1,12},{2,23},{1,11},{3,32},{2,21},{3,31},{1,10},{3,29},
{2,19},{3,28},{1, 9},{3,26},{2,17},{3,25},{1, 8},{4,31},{3,23},{2,15},{3,22},{4,29},{1, 7},{4,27},{3,20},{2,13},
{3,19},{4,25},{1, 6},{4,23},{3,17},{2,11},{3,16},{4,21},{1, 5},{4,19},{3,14},{2, 9},{3,13},{4,17},{1, 4},{4,15},
{3,11},{2, 7},{3,10},{4,13},{1, 3},{4,11},{3, 8},{2, 5},{3, 7},{4, 9},{1, 2},{4, 7},{3, 5},{2, 3},{3, 4},{4, 5},
{1,1},{4,3},{3,2},{2,1},{3,1},{4,1}
};
// sets framerate code and extensions
Status MPEG2VideoEncoderBase::SetFrameRate(Ipp64f new_fr, Ipp32s is_mpeg1)
{
const Ipp32s srsize = sizeof(sorted_ratio)/sizeof(sorted_ratio[0]);
const Ipp32s rtsize = sizeof(ratetab)/sizeof(ratetab[0]);
Ipp32s i, j, besti=0, bestj=0;
Ipp64f ratio, bestratio = 1.5;
Ipp32s fr1001 = (Ipp32s)(new_fr*1001+.5);
frame_rate_code = 5;
frame_rate_extension_n = frame_rate_extension_d = 0;
for(j=0;j<rtsize;j++) {
Ipp32s try1001 = (Ipp32s)(ratetab[j]*1001+.5);
if(fr1001 == try1001) {
frame_rate_code = j+1;
return UMC_OK;
}
}
if(is_mpeg1) { // for mpeg2 will find frame_rate_extention
return UMC_ERR_FAILED; // requires quite precise values: 0.05% or 0.02 Hz
}
if(new_fr < ratetab[0]/sorted_ratio[0][1]*0.7)
return UMC_ERR_FAILED;
for(j=0;j<rtsize;j++) {
ratio = ratetab[j] - new_fr; // just difference here
if(ratio < 0.0001 && ratio > -0.0001) { // was checked above with bigger range
frame_rate_code = j+1;
frame_rate_extension_n = frame_rate_extension_d = 0;
return UMC_OK;
}
if(!is_mpeg1)
for(i=0;i<srsize+1;i++) { // +1 because we want to analyze last point as well
if(ratetab[j]*sorted_ratio[i][0] > new_fr*sorted_ratio[i][1] || i==srsize) {
if(i>0) {
ratio = ratetab[j]*sorted_ratio[i-1][0] / (new_fr*sorted_ratio[i-1][1]); // up to 1
if(1/ratio < bestratio) {
besti = i-1;
bestj = j;
bestratio = 1/ratio;
}
}
if(i<srsize) {
ratio = ratetab[j]*sorted_ratio[i][0] / (new_fr*sorted_ratio[i][1]); // down to 1
if(ratio < bestratio) {
besti = i;
bestj = j;
bestratio = ratio;
}
}
break;
}
}
}
if(bestratio > 1.49)
return UMC_ERR_FAILED;
frame_rate_code = bestj+1;
frame_rate_extension_n = sorted_ratio[besti][0]-1;
frame_rate_extension_d = sorted_ratio[besti][1]-1;
return UMC_OK;
}
Status MPEG2VideoEncoderBase::SetAspectRatio(Ipp32s hor, Ipp32s ver) // sets aspect code from h/v value
{
if(hor*3 == ver*4) {
aspectRatio_code = 2;
encodeInfo.info.aspect_ratio_width = 4;
encodeInfo.info.aspect_ratio_height = 3;
} else if(hor*9 == ver*16) {
aspectRatio_code = 3;
encodeInfo.info.aspect_ratio_width = 16;
encodeInfo.info.aspect_ratio_height = 9;
} else if(hor*100 == ver*221) {
aspectRatio_code = 4;
encodeInfo.info.aspect_ratio_width = 221;
encodeInfo.info.aspect_ratio_height = 100;
} else {
Ipp64f ratio = (Ipp64f)hor/ver;
Ipp32s parx, pary;
Ipp32s w = encodeInfo.info.clip_info.width;
Ipp32s h = encodeInfo.info.clip_info.height;
// in video_data
DARtoPAR(w, h, hor, ver, &parx, &pary);
DARtoPAR(h, w, parx, pary,
&encodeInfo.info.aspect_ratio_width,
&encodeInfo.info.aspect_ratio_height); // PAR to DAR
if (parx == pary) aspectRatio_code = 1;
else if (ratio > 1.25 && ratio < 1.4) aspectRatio_code = 2;
else if (ratio > 1.67 && ratio < 1.88) aspectRatio_code = 3;
else if (ratio > 2.10 && ratio < 2.30) aspectRatio_code = 4;
else {
aspectRatio_code = 1;
vm_debug_trace(VM_DEBUG_WARNING, VM_STRING("Improper display aspect ratio"));
}
}
return UMC_OK;
}
#define SHIFT_PTR(oldptr, oldbase, newbase) \
( (newbase) + ( (Ipp8u*)(oldptr) - (Ipp8u*)(oldbase) ) )
Status MPEG2VideoEncoderBase::LockBuffers(void)
{
Ipp32s i;
Ipp8u* newptr;
if (m_lpbReference == 0) // wasn't allocated, error
return UMC_ERR_NOT_INITIALIZED;
newptr = (Ipp8u*) m_pMemoryAllocator->Lock(mid_Reference);
if(newptr != m_lpbReference) { //ptr changed, need to reset pointers
m_lpbReference = newptr;
for(i=0; i<4; i++) {
#ifdef ME_REF_ORIGINAL
SetInternalFramePointers(RotatingFrames[i],
m_lpbReference + i*YUVFrameSize);
#else
SetInternalFramePointers(RotatingFrames[i],
m_lpbReference + (i>>1)*YUVFrameSize);
#endif
}
}
if (frames_buff != 0 && is_frames_buff_locked == 0) {// nothing if hasn't been allocated
newptr = (Ipp8u*)m_pMemoryAllocator->Lock(mid_frames_buff);
if(newptr != frames_buff) { //ptr changed, need to reset pointers
if(!newptr) {
vm_debug_trace(VM_DEBUG_ERROR, VM_STRING("External Lock failed\n"));
return UMC_ERR_ALLOC;
}
frames_buff = newptr;
for(i=0; i<buff_size; i++) {
SetInternalFramePointers(VideoData_buff+i, frames_buff + i*YUVFrameSize);
}
}
}
if (tmpFrame_buf != 0) {// nothing if hasn't been allocated
newptr = (Ipp8u*)m_pMemoryAllocator->Lock(mid_tmpFrame_buf);
if(newptr != tmpFrame_buf) { //ptr changed, need to reset pointers
if(!newptr) {
vm_debug_trace(VM_DEBUG_ERROR, VM_STRING("External Lock failed\n"));
return UMC_ERR_ALLOC;
}
tmpFrame_buf = newptr;
SetInternalFramePointers(tmpFrame, tmpFrame_buf);
}
}
return UMC_OK;
}
Status MPEG2VideoEncoderBase::UnlockBuffers(void)
{
Status sts, ret;
ret = m_pMemoryAllocator->Unlock(mid_Reference);
if (frames_buff != 0) {// nothing if hasn't been allocated
sts = m_pMemoryAllocator->Unlock(mid_frames_buff);
if(ret==UMC_OK) ret = sts;
is_frames_buff_locked = 0;
}
if (tmpFrame_buf != 0) {// nothing if hasn't been allocated
sts = m_pMemoryAllocator->Unlock(mid_tmpFrame_buf);
if(ret==UMC_OK) ret = sts;
}
return ret;
}
#endif // UMC_ENABLE_MPEG2_VIDEO_ENCODER
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -