Using FFMPEG Audio conversion in the iPhone - iphone

I'm using ffmpeg in the iPhone, reading an wma stream from an mms server, but I want to save the stream to an m4a file using the ALAC encoder in ffmpeg, the problem is that trying to save the raw stream, the stream processed using avcodec_decode_audio2 , the file is not even recognized with the wma format, and obviously, not played, so before convert the stream to m4a (using avcodec_encode_audio) I want to be sure that the streaming is being processed and saved correctly. Anyone had experiencie doing this kind of stuff ? thanks
P.S. I'm writing the bytes buffer using CFWriteStreamWrite, and everything seems to be ok.
My code :
while (av_read_frame(mms_IOCtx, &_packet) >= 0) {
if (_packet.stream_index == audioStreamIdx) {
uint8_t *_packetData = _packet.data;
int _packetSize = _packet.size;
// Align output buffer
uint8_t audio_buf[(AVCODEC_MAX_AUDIO_FRAME_SIZE * 3) / 2 + 16];
int16_t *aligned_buffer;
size_t buffer_size;
int audio_size, len;
buffer_size = sizeof(audio_buf);
aligned_buffer = align16(audio_buf, &buffer_size);
while (currentState != STATE_CLOSED && (_packetSize > 0)) {
audio_size = buffer_size;
len = avcodec_decode_audio2(mms_CodecCtx, aligned_buffer, &audio_size, _packetData, _packetSize);
// call to the method that write the bytes ....
}
}
}

After decoding, it is no longer a WMA stream, it's a raw audio stream. If you want to write the WMA stream, you'd write out the data before decoding.

Related

Extract frames from pcap files (tcpdump output) without using Libraries

I need to parse the pcap files and count the packets separately (TCP,UDP,IP). I found a lot of libraries for this like pcap, jnetpcap but I want to do this without using any external libraries.I do not need a code but a just a conceptual explanation.
Question
While parsing pcap files how should I distinguish between the frames(be it TCP,UDP,IP). I tried reading about the format but what I do not understand is how would I come to know about how many bytes should I read for a particular frame and how would i know what type of a frame is it.Because only once I am able to extract the packets separately I will be able to filter out other information.
You'd have to parse each frame separately and have a counter for each value you are trying to count. Assuming the capture you are examining is in pcap/pcapng format you might find libpcap helpful.
To give a quick run of what you might have to do (assuming the lower level is Ethernet without VLAN tags)
uint64_t ip_count, tcp_count, udp_count;
void parse_pkt(uint8_t *data, uint32_t data_len) {
uint8_t *ether_hdr = data;
uint16_t ether_type = ntohs(*(uint16_t *) (data + 12))
if (ether_type != 0x800) {
return;
}
ip_count += 1;
uint8_t *ip_hdr = data + 14;
protocol = ntohs(*(uint16_t *) (ip_hdr + 9))
//protocol is either udp/tcp/sctp...etc
if (protocol == 0x11) {
udp_count++;
} else if (protocol == 0x06) {
tcp_count++;
}
}
// foreach pkt from libpcap_open call parse_pkt with the data and data_len
This code is fragile. Jumping to direct offsets without the proper length and type checks is not a good idea.

Using AVAssetWriter with raw NAL Units

I noticed in the iOS documentation for AVAssetWriterInput you can pass nil for the outputSettings dictionary to specify that the input data should not be re-encoded.
The settings used for encoding the media appended to the output. Pass nil to specify that appended samples should not be re-encoded.
I want to take advantage of this feature to pass in a stream of raw H.264 NALs, but I am having trouble adapting my raw byte streams into a CMSampleBuffer that I can pass into AVAssetWriterInput's appendSampleBuffer method. My stream of NALs contains only SPS/PPS/IDR/P NALs (1, 5, 7, 8). I haven't been able to find documentation or a conclusive answer on how to use pre-encoded H264 data with AVAssetWriter. The resulting video file is not able to be played.
How can I properly package the NAL units into CMSampleBuffers? Do I need to use a start code prefix? A length prefix? Do I need to ensure I only put one NAL per CMSampleBuffer? My end goal is to create an MP4 or MOV container with H264/AAC.
Here's the code I've been playing with:
-(void)addH264NAL:(NSData *)nal
{
dispatch_async(recordingQueue, ^{
//Adapting the raw NAL into a CMSampleBuffer
CMSampleBufferRef sampleBuffer = NULL;
CMBlockBufferRef blockBuffer = NULL;
CMFormatDescriptionRef formatDescription = NULL;
CMItemCount numberOfSampleTimeEntries = 1;
CMItemCount numberOfSamples = 1;
CMVideoFormatDescriptionCreate(kCFAllocatorDefault, kCMVideoCodecType_H264, 480, 360, nil, &formatDescription);
OSStatus result = CMBlockBufferCreateWithMemoryBlock(kCFAllocatorDefault, NULL, [nal length], kCFAllocatorDefault, NULL, 0, [nal length], kCMBlockBufferAssureMemoryNowFlag, &blockBuffer);
if(result != noErr)
{
NSLog(#"Error creating CMBlockBuffer");
return;
}
result = CMBlockBufferReplaceDataBytes([nal bytes], blockBuffer, 0, [nal length]);
if(result != noErr)
{
NSLog(#"Error filling CMBlockBuffer");
return;
}
const size_t sampleSizes = [nal length];
CMSampleTimingInfo timing = { 0 };
result = CMSampleBufferCreate(kCFAllocatorDefault, blockBuffer, YES, NULL, NULL, formatDescription, numberOfSamples, numberOfSampleTimeEntries, &timing, 1, &sampleSizes, &sampleBuffer);
if(result != noErr)
{
NSLog(#"Error creating CMSampleBuffer");
}
[self writeSampleBuffer:sampleBuffer ofType:AVMediaTypeVideo];
});
}
Note that I'm calling CMSampleBufferSetOutputPresentationTimeStamp on the sample buffer inside of the writeSampleBuffer method with what I think is a valid time before I'm actually trying to append it.
Any help is appreciated.
I managed to get video playback working in VLC but not QuickTime. I used code similar to what I posted above to get H.264 NALs into CMSampleBuffers.
I had two main issues:
I was not setting CMSampleTimingInfo correctly (as my comment above states).
I was not packing the raw NAL data correctly (not sure where this is documented, if anywhere).
To solve #1, I set timing.duration = CMTimeMake(1, fps); where fps is the expected frame rate. I then set timing.decodeTimeStamp = kCMTimeInvalid; to mean that the samples will be given in decoding order. Lastly, I set timing.presentationTimeStamp by calculating the absolute time, which I also used with startSessionAtSourceTime.
To solve #2, through trial and error I found that giving my NAL units in the following form worked:
[7 8 5] [1] [1] [1]..... [7 8 5] [1] [1] [1]..... (repeating)
Where each NAL unit is prefixed by a 32-bit start code equaling 0x00000001.
Presumably for the same reason it's not playing in QuickTime, I'm still having trouble moving the resulting .mov file to the photo album (the ALAssetLibrary method videoAtPathIsCompatibleWithSavedPhotosAlbum is failing stating that the "Movie could not be played." Hopefully someone with an idea about what's going on can comment. Thanks!

How to convert caf to mp3/amr?

Is there a way to convert the iphone record .caf files to .mp3 or amr files? Because the caf file need to upload, and server part can't use this format.
I am not familiar with audio processing. Here is my conclude :
The iphone sdk don't have a direct api to do this. We can only change the encoding format (AAC, IMA, iLBC, ALAC), see ACAudioFileConvert Demo. But it's still a caf file, I want to know if I can convert to mp3 by this.
Some guys suggest to use "LAME" api. Is anyone successful to use it in ios? Can anyone share a simple demo ?
Someone said it may cause a licence issue ?
Can anyone give me any advice ?
Sincere thanks!!!
It's quite simple:
int read, write;
FILE *pcm = fopen("file.caf", "rb");
FILE *mp3 = fopen("file.mp3", "wb");
const int PCM_SIZE = 8192;
const int MP3_SIZE = 8192;
short int pcm_buffer[PCM_SIZE*2];
unsigned char mp3_buffer[MP3_SIZE];
lame_t lame = lame_init();
lame_set_in_samplerate(lame, 44100);
lame_set_VBR(lame, vbr_default);
lame_init_params(lame);
do {
read = fread(pcm_buffer, 2*sizeof(short int), PCM_SIZE, pcm);
if (read == 0)
write = lame_encode_flush(lame, mp3_buffer, MP3_SIZE);
else
write = lame_encode_buffer_interleaved(lame, pcm_buffer, read, mp3_buffer, MP3_SIZE);
fwrite(mp3_buffer, write, 1, mp3);
} while (read != 0);
lame_close(lame);
fclose(mp3);
fclose(pcm);

AAC header and other info in iPhone

I'm building an iPhone Application that records sound. I make use of Audio Queue Services, and everything works great for the recording.
The thing is, I'm using AudioFileWritePackets for file writing, and I'm trying to put the same "AAC + ADTS" packets to a network socket.
The resulting file is different since some "headers" or "adts header" might be missing. I am searching for ideas on how to write the ADTS header and/or AAC header? Could the community assist me with this or refer me to a guide that demonstrated how to do this?
I currently have my Buffer Handler method:
void Recorder::MyInputBufferHandler(void inUserData,
AudioQueueRefinAQ, AudioQueueBufferRefinBuffer,
const AudioTimeStamp*inStartTime,
UInt32 inNumPackets,
const AudioStreamPacketDescription*inPacketDesc) {
AQRecorder *aqr = (AQRecorder *)inUserData;
try {
if (inNumPackets > 0) {
// write packets to file
XThrowIfError(AudioFileWritePackets(aqr->mRecordFile,
FALSE,
inBuffer->mAudioDataByteSize,
inPacketDesc,
aqr->mRecordPacket,
&inNumPackets,
inBuffer->mAudioData),
"AudioFileWritePackets failed");
fprintf(stderr, "Writing.");
// We write the Net Buffer.
[aqr->socket_if writeData :(void *)(inBuffer->mAudioData)
:inBuffer->mAudioDataByteSize];
aqr->mRecordPacket += inNumPackets;
}
// if we're not stopping, re-enqueue the buffe so that it gets filled again
if (aqr->IsRunning()) {
XThrowIfError(AudioQueueEnqueueBuffer(inAQ, inBuffer, 0, NULL),
"AudioQueueEnqueueBuffer failed");
}
}
catch (CAXException e) {
char buf[256];
fprintf(stderr, "Error: %s (%s)\n", e.mOperation, e.FormatError(buf));
}
}
I've found the solution for this:
I implemented the callback
XThrowIfError(
AudioFileInitializeWithCallbacks(
this,
nil,
BufferFilled_callback,
nil,
nil,
//kAudioFileCAFType,
kAudioFileAAC_ADTSType,
&mRecordFormat,
kAudioFileFlags_EraseFile,
&mRecordFile),
"InitializeWithCallbacks failed");
... And voilá! The real callback you have to implement is BufferFilled_callback. Here is my implementation:
OSStatus AQRecorder::BufferFilled_callback(
void * inUserData,
SInt64 inPosition,
UInt32 requestCount,
const void * buffer,
UInt32 * actualCount) {
AQRecorder *aqr = (AQRecorder *)inUserData;
// You can write these bytes to anywhere.
// You can build a streaming server
return 0;
}
If you want to see more about audio queue services, you can get some ideas from Flipzu for iPhone (ex-app for live broadcasting audio // we have to shut it down because we could not raise money).
https://github.com/lucaslain/Flipzu_iPhone
Best,
Lucas.
I've recently encountered this issue with the iLBC codec, and arrived at the solution as follows:
Record the audio data you want and just write it to a file. Then, take that file and do an octal dump on it. You can use the -c flag to see ascii characters.
Then, create a separate file that you know doesn't contain the header. This is just your data from the buffers on the audio queue. Octal dump that, and compare.
From this, you should have the header and enough info on how to proceed. Hope this helps.

How to get the uncompressed file size of an MP3 file using CoreAudio API

Using CoreAudio, I am able to get the sampleRate (frames per second) and the file size, but in order to get the "total" time of the song, I need to know the Real file size of that compressed mp3.
AudioStreamBasicDescription asbd;
UInt32 asbdSize = sizeof(asbd);
// get the stream format.
err = AudioFileStreamGetProperty(inAudioFileStream, kAudioFileStreamProperty_DataFormat, &asbdSize, &asbd);
if (err)
{
[self failWithErrorCode:AS_FILE_STREAM_GET_PROPERTY_FAILED];
return;
}
sampleRate = asbd.mSampleRate;
Is there any way I can know the real size of the song using Objective-C?
Thanks in advance.
See the answer to this question
There's a property you can ask in AudioFileGetProperty called kAudioFilePropertyEstimatedDuration that should do the trick.