GPUImageMovieWriter录制视频问题

来源:互联网 发布:java 写入word 编辑:程序博客网 时间:2024/04/29 19:50
GPUImageMovieWriter录制视频问题
1、两个movie叠加的时候,每个movie解码出一帧都会走到GPUImageTwoInputFilter的newFrameReadyAtTime

- (void)newFrameReadyAtTime:(CMTime)frameTime atIndex:(NSInteger)textureIndex;

{

    // You can set up infinite update loops, so this helps to short circuit them

    if (hasReceivedFirstFrame && hasReceivedSecondFrame)

    {

        return;

    }

    

    BOOL updatedMovieFrameOppositeStillImage = NO;

      if (textureIndex == 0)

    {

        hasReceivedFirstFrame = YES;

        firstFrameTime = frameTime;

        if (secondFrameCheckDisabled)

        {

            hasReceivedSecondFrame = YES;

        }

        

        if (!CMTIME_IS_INDEFINITE(frameTime))

        {

            if CMTIME_IS_INDEFINITE(secondFrameTime)

            {

                updatedMovieFrameOppositeStillImage = YES;

            }

        }

    }

    else

    {

        hasReceivedSecondFrame = YES;

        secondFrameTime = frameTime;

        if (firstFrameCheckDisabled)

        {

            hasReceivedFirstFrame = YES;

        }

        if (!CMTIME_IS_INDEFINITE(frameTime))

        {

            if CMTIME_IS_INDEFINITE(firstFrameTime)

            {

                updatedMovieFrameOppositeStillImage = YES;

            }

        }

    }


    // || (hasReceivedFirstFrame && secondFrameCheckDisabled) || (hasReceivedSecondFrame && firstFrameCheckDisabled)

    if ((hasReceivedFirstFrame && hasReceivedSecondFrame) || updatedMovieFrameOppositeStillImage)

    {

        CMTime passOnFrameTime = (!CMTIME_IS_INDEFINITE(firstFrameTime)) ? firstFrameTime : secondFrameTime;

        [super newFrameReadyAtTime:passOnFrameTime atIndex:0]; // Bugfix when trying to record: always use time from first input (unless indefinite, in which case use the second input)

        hasReceivedFirstFrame = NO;

        hasReceivedSecondFrame = NO;

    }

}

因为两个movie在不同的线程,如果2个movie帧率不一样,因为录制的时候是全速的,这样可能movie1已经来到上面方法很多次,而movie2才来一帧,这样就导致movie1

丢失了帧。解决方法:

- (BOOL)readNextVideoFrameFromOutput:(AVAssetReaderOutput *)readerVideoTrackOutput;

{

    if (reader.status == AVAssetReaderStatusReading && ! videoEncodingIsFinished)

    {

        CMSampleBufferRef sampleBufferRef = [readerVideoTrackOutput copyNextSampleBuffer];

        if (sampleBufferRef) 

        {


            if (_playAtActualSpeed)

            {

               ...

            }else{

               //这里判断另外一个movie是否准备,没准备就等一下

            }


            __unsafe_unretained GPUImageMovie *weakSelf = self;

            runSynchronouslyOnVideoProcessingQueue(^{

                [weakSelf processMovieFrame:sampleBufferRef];

                CMSampleBufferInvalidate(sampleBufferRef);

                CFRelease(sampleBufferRef);

            });


            return YES;

        }

        else

        {

            if (!keepLooping) {

                videoEncodingIsFinished = YES;

                if( videoEncodingIsFinished && audioEncodingIsFinished )

                    [self endProcessing];

            }

        }

    }

    else if (synchronizedMovieWriter != nil)

    {

        if (reader.status == AVAssetReaderStatusCompleted)

        {

            [self endProcessing];

        }

    }

    return NO;

}



2、使用GPUImageMovieWriter的processAudioBuffer写音频时,如果是写太快,可能导致音频丢失,可以在线程中sleep一下。

 When expectsMediaDataInRealTime is YES, readyForMoreMediaData will become NO only when the input cannot process media samples as quickly as they are being provided by the client. If readyForMoreMediaData becomes NO for a real-time source, the client may need to drop samples or consider reducing the data rate of appended samples.


3、使用GPUImageThreeInput,需要自己写fragment shafer,init的时候传入。


0 0