How can I record only one second audio sound without using file system and convert it to a byte array to send it by JSON?
NSDictionary *recordSettings = [NSDictionary
dictionaryWithObjectsAndKeys:
[NSNumber numberWithInt:AVAudioQualityMin],
AVEncoderAudioQualityKey,
[NSNumber numberWithInt:16],
AVEncoderBitRateKey,
[NSNumber numberWithInt: 1],
AVNumberOfChannelsKey,
[NSNumber numberWithFloat:16000.0], AVSampleRateKey,
[NSNumber numberWithInt:8], AVLinearPCMBitDepthKey,
nil];
recorder = [[AVAudioRecorder alloc] initWithURL:recordedFile settings:recordSettings error:nil];
Else, I wanna know how size is this one second sound recorded and time.
Sample rate = 16,000 Hz (samples per second)
Bit rate = 16 (bits per sample)
Therefore size of 1 second sample = 16K x 16 = 256Kbits
To record one second, you can use
- (BOOL)recordForDuration:(NSTimeInterval)duration
If you want a fast start, you can prime the recording beforehand using
- (void)prepareToRecord
For recording at a specific time, use
- (BOOL)recordAtTime:(NSTimeInterval)time
forDuration:(NSTimeInterval)duration
(which implicitly calls prepareToRecord)
To get an accurate time of recording you will need to use a lower-level API. If you are not worried about accuracy, you can log the time you call the above method or the time it is written to the filesystem.
If you don't want to use the filesystem then you will need to use a lower-level API where you can get at the bitstream using a callback. Apple's Core Audio, or one of the many C++ audio engines (e.g. PortAudio, FMod, Novocaine) will let you do this.
Related
I'm capturing the camera feed and writing it to a movie.
The problem I'm having is that after the export the movie has a couple of black seconds in front of it (relative to the actual recording start time).
I think this is related to [self.assetWriter startSessionAtSourceTime:kCMTimeZero];
I had a half working solution by having a frameStart variable that just counted upwards in the samplebuffer delegate method.
- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection {
CVPixelBufferRef pixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer);
frameStart++;
if (self.startRecording == YES) {
static int64_t frameNumber = 0;
if(self.assetWriterInput.readyForMoreMediaData) {
[self.pixelBufferAdaptor appendPixelBuffer:pixelBuffer withPresentationTime:CMTimeMake(frameNumber, 25)];
}
frameNumber++;
}
}
and then call this method when the user pressed a button:
[self.assetWriter startSessionAtSourceTime:CMTimeMake(frameStart,25)];
this works. but only once... if I want to record a second movie the black frames are back again.
Also, when I look at the outputted movie the frame rate is 25fps like I want it to. but the video looks as if it's sped up. as if there is not enough space between the frames. So the movie plays about twice as fast.
NSDictionary *outputSettings = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithInt:640], AVVideoWidthKey, [NSNumber numberWithInt:480], AVVideoHeightKey, AVVideoCodecH264, AVVideoCodecKey, nil];
self.assetWriterInput = [AVAssetWriterInput assetWriterInputWithMediaType:AVMediaTypeVideo outputSettings:outputSettings];
self.assetWriterInput.expectsMediaDataInRealTime = YES;
You don't need to count frame timestamps on your own. You can get the timestamp of the current sample with
CMTime timestamp = CMSampleBufferGetPresentationTimeStamp(sampleBuffer);
However, it seems to me you are just passing the pixel buffer of the frame to the adaptor without modifications. Wouldn't it be easier to pass the sample buffer itself directly to the assetWriterInput like the following?
[self.assetWriterInput appendSampleBuffer:sampleBuffer];
First of all, why are you incrementing frameNumber twice for every frame?
Increment once, remove the first one.
This should fix the playback speed.
Second, are you resetting frameNumber to 0 when you finish recording?
If not than this is your problem.
If not I need more explanation about what is going on here..
Regards
Which audio format is small in size for speech recording in ios? The quality is need not to be the best but it should be understandable what user speaks.
Assuming you plan to use AVAudioRecorder class, you should provide the recording settings like so -
NSDictionary *recordSettings = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithInt:AVAudioQualityMin], AVEncoderAudioQualityKey,
[NSNumber numberWithInt:16], AVEncoderBitRateKey,
[NSNumber numberWithInt: 2],AVNumberOfChannelsKey,
[NSNumber numberWithFloat:44100.0], AVSampleRateKey,nil];
NSError* error = nil;
AVAudioRecorder audioRecorder = [[AVAudioRecorder alloc]
initWithURL:soundFileURL
settings:recordSettings
error:&error];
Apple's documentation provides details about the settings constants (specifically AVEncoderAudioQualityKey) you could use in your app.
22.05KHz in mono is more than adequate for speech and is 1/4 the size of 44.1KHz in stereo at the same bit depth. You could likely even try dropping it down to 11.025KHz.
Several iOS apps use the Speex encoder for lower-bit rate speech. It's not built-in, but open source source code is available to do the encoding.
I make a FFMPEG-based player for ios. It works fine on simulator, but on real-device (iPhone 4) the frame rate is low and make my audio and video out of sync. the player works fine on iPhone 4s, so I guess it's just problem about device's computing power.
So, is there anyway to build FFMPEG optimized for iOS device (armv7, arvm7s arch)? or is there anyway to utilize ios device hardware to decode video stream?
My video stream is encode in H264/AAC.
Those streams should play just fine, I assume since your using ffmpeg you are not using a video protocol that iOS supports directly.
We use ffmpeg to do rtsp/rtmp and we get good performance with h264/aac
There are a number of factors that contribute to av/sync issues, usually some type of pre-buffering of the video is required, also network plays a big part in it.
As to your second question, hardware encoding is only available via avfoundation, you can use avassetwriter to encode your video, but again depends wether or not you need real-time.
see this link https://github.com/mooncatventures-group/FFPlayer-beta1/blob/master/FFAVFrames-test/ViewController.m
-(void) startRecording {
// // create the AVComposition
// [mutableComposition release];
// mutableComposition = [[AVMutableComposition alloc] init];
movieURL = [NSURL fileURLWithPath:[NSString stringWithFormat:#"%#/%llu.mov", NSTemporaryDirectory(), mach_absolute_time()]];
NSError *movieError = nil;
assetWriter = [[AVAssetWriter alloc] initWithURL:movieURL
fileType: AVFileTypeQuickTimeMovie
error: &movieError];
NSDictionary *assetWriterInputSettings = [NSDictionary dictionaryWithObjectsAndKeys:
AVVideoCodecH264, AVVideoCodecKey,
[NSNumber numberWithInt:FRAME_WIDTH], AVVideoWidthKey,
[NSNumber numberWithInt:FRAME_HEIGHT], AVVideoHeightKey,
nil];
assetWriterInput = [AVAssetWriterInput assetWriterInputWithMediaType: AVMediaTypeVideo
outputSettings:assetWriterInputSettings];
assetWriterInput.expectsMediaDataInRealTime = YES;
[assetWriter addInput:assetWriterInput];
assetWriterPixelBufferAdaptor = [[AVAssetWriterInputPixelBufferAdaptor alloc]
initWithAssetWriterInput:assetWriterInput
sourcePixelBufferAttributes:nil];
[assetWriter startWriting];
firstFrameWallClockTime = CFAbsoluteTimeGetCurrent();
[assetWriter startSessionAtSourceTime:kCMTimeZero];
startSampleing=YES;
}
The one drawback right now is that a way needs to be determined to read the encoded data as its being written, believe me when I say there are a few of us developers trying to figure out how to do that as we I write this.
I've got a live app with an estimated 15% of users reporting that the record feature is not working. This isn't happening on our test devices, but the reports show that the problem is that prepareToRecord is returning NO. I've had trouble finding sample settings for AAC format. Are any of my settings off? App requires iOS5 and uses ARC.
AVAudioSession *audioSession = [AVAudioSession sharedInstance];
[audioSession setCategory:AVAudioSessionCategoryRecord error:nil];
NSDictionary *recordSettings = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithInt:kAudioFormatMPEG4AAC], AVFormatIDKey,
[NSNumber numberWithFloat:44100.0], AVSampleRateKey,
[NSNumber numberWithInt:1], AVNumberOfChannelsKey,
[NSNumber numberWithInt:AVAudioQualityHigh], AVSampleRateConverterAudioQualityKey,
[NSNumber numberWithInt:128000], AVEncoderBitRateKey,
[NSNumber numberWithInt:16], AVEncoderBitDepthHintKey,
nil];
NSString *fileName = [NSString stringWithFormat:#"%#%#.caf", verseGUID, bRecordingReference ? #"_ref" : #""];
NSURL *url = [NSURL fileURLWithPath:[NSString stringWithFormat:#"%#/%#", [[Utilities sharedInstance] documentsDirectoryPath], fileName]];
NSError *error = nil;
audioRecorder = [[AVAudioRecorder alloc] initWithURL:url settings:recordSettings error:&error];
if([audioRecorder prepareToRecord]){
[audioRecorder record];
}else{
int errorCode = CFSwapInt32HostToBig([error code]);
NSLog(#"Error: %# [%4.4s])", [error localizedDescription], (char*)&errorCode);
}
it could be many things not having to do with the recording settings.
the real question you want answered seems to be: what would cause the recording not to occur?
audioRecorder could be nil or audioRecorder prepareToPlay could be returning NO. the former seems more likely.
the url passed to initWithURL could be malformed:
- have you tested by playing with the verseGUID, bRecordReference values? maybe your devices never have a bad verseGUID, but the devices on which no recording happens have a nil/empty verseGUID. this could cause the filename to be simply ".caf".
you seem to have your own class method [Utilities sharedInstance] . could this work for some reason on your devices but not on the failing devices? if so, you could be asking to record in a top level directory when you did not mean to.
can you get the testers you have onto a "beta" list? sign up for something like TestFlight or Hockey Kit, get one or more of the users with a failure to record to also sign up, and then upload a beta of your app with diagnostics that put a dialog on screen with the resultant "error". that might be most obvious. i use testflightapp.com only because it was the first i tried, it was pretty easy for me to manage and pretty painless for my beta testers.
Try this settings which i used to record MPEG 4 AAC format...Its working good..
NSString *tempDir = NSTemporaryDirectory();
NSString *soundFilePath = [tempDir stringByAppendingPathComponent:#"sound.m4a"];
NSURL *soundFileURL = [NSURL fileURLWithPath:soundFilePath];
NSDictionary *recordSettings = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithInt:kAudioFormatMPEG4AAC], AVFormatIDKey,
[NSNumber numberWithInt:AVAudioQualityMin], AVEncoderAudioQualityKey,
[NSNumber numberWithInt: 1], AVNumberOfChannelsKey,
[NSNumber numberWithFloat:8000.0], AVSampleRateKey,
nil];
Apologies that this is slightly tangential but I've just had a very similar issue with a number of users not being able to record, which I thought was related to audio settings.
However for me it turned out that they had denied permission to access the microphone. This meant that prepareToRecord was working (and truncating the file) and record was reporting that it was working, but actually it wasn't recording anything.
And I used this when I want to record:
AVAudioSession.sharedInstance().requestRecordPermission({(granted: Bool)-> Void in
if granted {
// can record - create AVAudioRecorder here
} else {
// can't record - update UI (or react accordingly)
}
})
Hope it saves someone some time if they run into a similar issue.
I am a newbie in AVFoundation and decoding process.I need to decode a h264 video file and play it in iphone...can anyone give me guideline to do it.
I dont want to use ffmpeg or any third party library to do that. As far as I know using Avfoundation encoding is possible...here is the code which I thought is used for encoding but not sure at all...
float bitsPerPixel;
CMVideoDimensions dimensions = CMVideoFormatDescriptionGetDimensions(currentFormatDescription);
int numPixels = dimensions.width * dimensions.height;
int bitsPerSecond;
// Assume that lower-than-SD resolutions are intended for streaming, and use a lower bitrate
if ( numPixels < (640 * 480) )
bitsPerPixel = 4.05; // This bitrate matches the quality produced by AVCaptureSessionPresetMedium or Low.
else
bitsPerPixel = 11.4; // This bitrate matches the quality produced by AVCaptureSessionPresetHigh.
bitsPerSecond = numPixels * bitsPerPixel;
NSDictionary *videoCompressionSettings = [NSDictionary dictionaryWithObjectsAndKeys:
AVVideoCodecH264, AVVideoCodecKey,
[NSNumber numberWithInteger:dimensions.width], AVVideoWidthKey,
[NSNumber numberWithInteger:dimensions.height], AVVideoHeightKey,
[NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithInteger:bitsPerSecond], AVVideoAverageBitRateKey,
[NSNumber numberWithInteger:30], AVVideoMaxKeyFrameIntervalKey,
nil], AVVideoCompressionPropertiesKey,
nil];
if ([assetWriter canApplyOutputSettings:videoCompressionSettings forMediaType:AVMediaTypeVideo]) {
assetWriterVideoIn = [[AVAssetWriterInput alloc] initWithMediaType:AVMediaTypeVideo outputSettings:videoCompressionSettings];
assetWriterVideoIn.expectsMediaDataInRealTime = YES;
assetWriterVideoIn.transform = [self transformFromCurrentVideoOrientationToOrientation:self.referenceOrientation];
if ([assetWriter canAddInput:assetWriterVideoIn])
[assetWriter addInput:assetWriterVideoIn];
else {
NSLog(#"Couldn't add asset writer video input.");
return NO;
}
}
else {
NSLog(#"Couldn't apply video output settings.");
return NO;
}
return YES;
I am completely naive about this, please help...from where to start///
thanks
The simpler solution is to use MPMoviePlayerController. It takes in input a mov or mv4 file (from local file system or through an URL).
The another option is to use AVPlayer class.
Hope it helps,
David
You can refer and build the official sample code: AVPlayerDemo to see how it works. It uses AV Foundation framework, mainly the AVPlayer APIs to play video files and the performance is excellent.
To play a video file by AVPlayerDemo you should copy the video files to your iOS device by itunes and select iPod library on the AVPlayerDemo App.