I am trying to read and write the samples from a video file at a specific start point and end point for trimming a video. I am using AVAssetReader and AVAssetWriter.
The logic used here is -
STEP A:
- Create asset reader instance with the specified asset.
- Set the time range to the reader as per the start and end points. ( Say for example - start point = 5, end point = 15, file length = 55 sec )
- Start reading the samples.
- Get the sample's exact time stamp with respect to start point that we have passed in.
- Store the time stamp of the sample that is accurate with the start point.( could be 5.13 or so ). Say ta = 5.13
- Release the reader.
STEP B:
- Create a new reader instance with the specified asset.
- Set the time range to the reader as per the start and end points. ( Say for example - start point = 5, end point = 15, file length = 55 sec )
- Start reading the samples.
- Create a new sample buffer with sample timing info altered as ( sample buffer's time stamp t1- ta fetched from STEP A ) - This starts to write from 0 ( sample buffer's time stamp t2- ta fetched from STEP A ) ( sample buffer's time stamp t3- ta fetched from STEP A ) and so on till end point.
- Release the reader.
The code sample for the same is:
STEP A:
while ([assetWriterInput isReadyForMoreMediaData] )
{
CMSampleBufferRef sampleBuffer = [assetReaderOutput copyNextSampleBuffer];
if (sampleBuffer != NULL)
{
CMTime originalTime = CMSampleBufferGetPresentationTimeStamp(sampleBuffer);
float time = CMTimeGetSeconds( originalTime );
// This is where we store the time stamp
fTimeTange = time;
[HelpMethods setCorrectEditTime:fTimeTange]; // This is stored globally
// This is to release the readers and writers and start a fresh call with the stored time stamp ta
[delegate resetTimeRange];
return;
}
}
STEP B:
while ([assetWriterInput isReadyForMoreMediaData] )
{
CMSampleBufferRef sampleBuffer = [assetReaderOutput copyNextSampleBuffer];
if (sampleBuffer != NULL)
{
CMSampleBufferRef finalBuffer = sampleBuffer;
CMSampleBufferRef newSampleBuffer;
CMSampleTimingInfo sampleTimingInfo;
CMTime cmm1 = CMSampleBufferGetOutputDuration(sampleBuffer);
CMTime originalTime = CMSampleBufferGetPresentationTimeStamp(sampleBuffer);
float time = CMTimeGetSeconds( originalTime );
// This is a helper method to get the stored ta at STEP A
fTimeTange = [HelpMethods getCorrectEditTime];
sampleTimingInfo.duration = cmm1;
float milliseconds = (time - fTimeTange) * 600;
NSLog( @"Timestamp in milliseconds = %f", milliseconds );
sampleTimingInfo.presentationTimeStamp = CMTimeMake(milliseconds, 600);
sampleTimingInfo.decodeTimeStamp = kCMTimeInvalid;
CMSampleBufferCreateCopyWithNewTiming(kCFAllocatorDefault,
sampleBuffer,
1,
&sampleTimingInfo,
&newSampleBuffer);
finalBuffer = newSampleBuffer;
BOOL success = YES;
success = [assetWriterInput appendSampleBuffer:finalBuffer];
CFRelease(sampleBuffer);
sampleBuffer = NULL;
}
Since the time stamps of the samples are read in out of order fashion, we end up getting an error saying
"(kFigFormatWriterError_InvalidTimestamp) (decode timestamp is less than previous sample's decode timestamp)"
and the values of time stamps are -
- Timestamp in milliseconds = 0.000000
- Timestamp in milliseconds = 79.999924
- Timestamp in milliseconds = 39.999962
- Timestamp in milliseconds = 119.999886
- Timestamp in milliseconds = 200.000092
- Timestamp in milliseconds = 160.000137
- Timestamp in milliseconds = 280.000031
- Timestamp in milliseconds = 240.000061
- Timestamp in milliseconds = 319.999969
- Timestamp in milliseconds = 399.999908
- Timestamp in milliseconds = 359.999939 and so on
Any manipulation done to the presentation stamps results in out of order reading of samples.
Looking out a way to overcome this out of order reading of timestamps. Please let know.
Thanks in advance, Champa