H.264编码器在需要时强制插入关键帧

  • Post author:
  • Post category:其他


废话不多说,直接上关键部分的代码


-(void)encode:(CMSampleBufferRef)sampleBuffer isCrop:(BOOL)isCrop
{
    log4cplus_debug("h264", "encoder video data\n");
    if (self.error) {
        log4cplus_error("h264", "error = %d",self.error);
    }
    if(self.error == Error_Restart5TimesStillFailured)
    {
        log4cplus_debug("h264", "%s,restart encoder more than 5 times, %d",__func__,__LINE__);
        [self.delegate didRestartFailured];
    }

    [m_lock lock];
    if(self.isReadyForEncode)
    {
        if(compressionSession == NULL)
        {
            log4cplus_error("h264", "%s,compressionSession =null, %d",__func__,__LINE__);
            goto RELEASE_BUFFER;
        }

        //the first frame must be iframe then create the reference timeStamp;
        static BOOL isFirstFrame = YES;
        if(isFirstFrame)
        {
            CMTime pts = CMSampleBufferGetPresentationTimeStamp(sampleBuffer);
            log4cplus_info("h264","g_vstarttime = %f",CMTimeGetSeconds(pts));
            g_vstarttime = CMTimeGetSeconds(pts);// system absolutly time(s)
            g_tvustartcaptureTime = CTimeThread::GetCurrentTime();
            if(ntp_time_offset != 0)
            {
                g_tvustartcaptureTime = g_tvustartcaptureTime - (ntp_time_offset/1000);
            }

            log4cplus_error("h264","CAPTURETIME = %u, %ld",g_tvustartcaptureTime, ntp_time_offset);
            isFirstFrame = NO;
        }

        if(initialized == false){
            log4cplus_error("h264", "h264 encoder is not ready\n");
            goto RELEASE_BUFFER;
        }

        [self doSetBitrate];

        CVImageBufferRef imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer);
        CMTime presentationTimeStamp = CMSampleBufferGetPresentationTimeStamp(sampleBuffer);


     // 关键步骤  begin   
        OSStatus status = noErr;       
        if (g_needForceInsertKeyFrame) {
            NSDictionary *properties = @{(__bridge NSString *)kVTEncodeFrameOptionKey_ForceKeyFrame:@YES};
            status = VTCompressionSessionEncodeFrame(compressionSession, imageBuffer, presentationTimeStamp, kCMTimeInvalid, (__bridge CFDictionaryRef)properties, NULL, NULL);//  强制插入关键帧    (__bridge CFDictionaryRef)properties  该参数必须设置为YES,并在编码时传入,就能立即插入一帧关键帧
            g_needForceInsertKeyFrame = false;
        }else {
            status = VTCompressionSessionEncodeFrame(compressionSession, imageBuffer, presentationTimeStamp, kCMTimeInvalid, NULL, NULL, NULL);
        }

     // 关键步骤  end    

        //NSAssert(status == noErr, @"assert : Encoder frame failured!");

        if(status != noErr)
        {
            NSLog(@"H264: VTCompressionSessionEncodeFrame failed");
            VTCompressionSessionCompleteFrames(compressionSession, kCMTimeInvalid);
            VTCompressionSessionInvalidate(compressionSession);
            CFRelease(compressionSession);
            compressionSession = NULL;
            _error = Error_EncodeFrameFailured;
            [m_lock unlock];
            if (isCrop) {
                if (sampleBuffer != NULL) {
                    CFRelease(sampleBuffer);
                    log4cplus_debug("h264", "Release crop sample buffer");
                }
            }
            [self.delegate didEncoderErrorOccured:Error_EncodeFrameFailured];
            return;
        }
    }

    // if sample buffer are from system needn't to release, if sample buffer are from we create need to release.
RELEASE_BUFFER:
    [m_lock unlock];
    if (isCrop) {
        if (sampleBuffer != NULL) {
            CFRelease(sampleBuffer);
            log4cplus_debug("h264", "Release crop sample buffer");
        }
    }
}






版权声明:本文为GZgengzhen原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。