Audio Frames repeating in AVFramework created *.mov file via AVAsset - audio

I am running into some problems trying to create a ProRes encoded mov file using the AVFramework framework, and AVAsset.
On OSX 10.10.5, using XCode 7, linking against 10.9 libraries.
So far I have managed to create valid ProRes files that contain both video and multiple channels of audio.
( I am creating multiple tracks of uncompressed 48K, 16-bit PCM Audio)
Adding the Video Frames work well, and adding the Audio frames works well, or at least succeeds in the code.
However when i play the file back, it appears as though the audio frames are repeated, in 12,13,14, or 15 frame sequences.
Looking at the wave form, from the *.mov it is easy to see the repeated audio...
That is to say, the first 13 or X video frames all contain exactly the same audio, this is then again repeated for the next X, and then again and again and again etc...
The Video is fine, it is just the Audio that appears to be looping/repeating.
The issue appears no matter how many audio channels/ tracks I use as the source, I have tested using just 1 track and also using 4 and 8 tracks.
It is independent of what format and amount of samples i feed to the system, ie using, 720p60, 1080p23, and 1080i59 all exhibit the same incorrect behavior.
well actually the 720p captures appears to repeat the audio frames 30 or 31 times, and the 1080 formats only repeat the audio frames 12 or 13 times,
But i am definitely submitting different audio data to the Audio encode/SampleBuffer create process, as i have logged this in great detail ( tho it is not shown in the code below)
I have tried a number of different things to modify the code and expose the issue, but had no success, hence i am asking here, and hopefully someone can either see an issue with my code or give me some info with regards to this problem.
The code i am using is as follows:
int main(int argc, const char * argv[])
{
#autoreleasepool
{
NSLog(#"Hello, World! - Welcome to the ProResCapture With Audio sample app. ");
OSStatus status;
AudioStreamBasicDescription audioFormat;
CMAudioFormatDescriptionRef audioFormatDesc;
// OK so lets include the hardware stuff first and then we can see about doing some actual capture and compress stuff
HARDWARE_HANDLE pHardware = sdiFactory();
if (pHardware)
{
unsigned long ulUpdateType = UPD_FMT_FRAME;
unsigned long ulFieldCount = 0;
unsigned int numAudioChannels = 4; //8; //4;
int numFramesToCapture = 300;
gBFHancBuffer = (unsigned int*)myAlloc(gHANC_SIZE);
int audioSize = 2002 * 4 * 16;
short* pAudioSamples = (short*)new char[audioSize];
std::vector<short*> vecOfNonInterleavedAudioSamplesPtrs;
for (int i = 0; i < 16; i++)
{
vecOfNonInterleavedAudioSamplesPtrs.push_back((short*)myAlloc(2002 * sizeof(short)));
}
bool bVideoModeIsValid = SetupAndConfigureHardwareToCaptureIncomingVideo();
if (bVideoModeIsValid)
{
gBFBytes = (BLUE_UINT32*)myAlloc(gGoldenSize);
bool canAddVideoWriter = false;
bool canAddAudioWriter = false;
int nAudioSamplesWritten = 0;
// declare the vars for our various AVAsset elements
AVAssetWriter* assetWriter = nil;
AVAssetWriterInput* assetWriterInputVideo = nil;
AVAssetWriterInput* assetWriterAudioInput[16];
AVAssetWriterInputPixelBufferAdaptor* adaptor = nil;
NSURL* localOutputURL = nil;
NSError* localError = nil;
// create the file we are goijmng to be writing to
localOutputURL = [NSURL URLWithString:#"file:///Volumes/Media/ProResAVCaptureAnyFormat.mov"];
assetWriter = [[AVAssetWriter alloc] initWithURL: localOutputURL fileType:AVFileTypeQuickTimeMovie error:&localError];
if (assetWriter)
{
assetWriter.shouldOptimizeForNetworkUse = NO;
// Lets configure the Audio and Video settings for this writer...
{
// Video First.
// Add a video input
// create a dictionary with the settings we want ie. Prores capture and width and height.
NSMutableDictionary* videoSettings = [NSMutableDictionary dictionaryWithObjectsAndKeys:
AVVideoCodecAppleProRes422, AVVideoCodecKey,
[NSNumber numberWithInt:width], AVVideoWidthKey,
[NSNumber numberWithInt:height], AVVideoHeightKey,
nil];
assetWriterInputVideo = [AVAssetWriterInput assetWriterInputWithMediaType: AVMediaTypeVideo outputSettings:videoSettings];
adaptor = [AVAssetWriterInputPixelBufferAdaptor assetWriterInputPixelBufferAdaptorWithAssetWriterInput:assetWriterInputVideo
sourcePixelBufferAttributes:nil];
canAddVideoWriter = [assetWriter canAddInput:assetWriterInputVideo];
}
{ // Add a Audio AssetWriterInput
// Create a dictionary with the settings we want ie. Uncompressed PCM audio 16 bit little endian.
NSMutableDictionary* audioSettings = [NSMutableDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithInt:kAudioFormatLinearPCM], AVFormatIDKey,
[NSNumber numberWithFloat:48000.0], AVSampleRateKey,
[NSNumber numberWithInt:16], AVLinearPCMBitDepthKey,
[NSNumber numberWithBool:NO], AVLinearPCMIsNonInterleaved,
[NSNumber numberWithBool:NO], AVLinearPCMIsFloatKey,
[NSNumber numberWithBool:NO], AVLinearPCMIsBigEndianKey,
[NSNumber numberWithUnsignedInteger:1], AVNumberOfChannelsKey,
nil];
// OR use... FillOutASBDForLPCM(AudioStreamBasicDescription& outASBD, Float64 inSampleRate, UInt32 inChannelsPerFrame, UInt32 inValidBitsPerChannel, UInt32 inTotalBitsPerChannel, bool inIsFloat, bool inIsBigEndian, bool inIsNonInterleaved = false)
UInt32 inValidBitsPerChannel = 16;
UInt32 inTotalBitsPerChannel = 16;
bool inIsFloat = false;
bool inIsBigEndian = false;
UInt32 inChannelsPerTrack = 1;
FillOutASBDForLPCM(audioFormat, 48000.00, inChannelsPerTrack, inValidBitsPerChannel, inTotalBitsPerChannel, inIsFloat, inIsBigEndian);
status = CMAudioFormatDescriptionCreate(kCFAllocatorDefault,
&audioFormat,
0,
NULL,
0,
NULL,
NULL,
&audioFormatDesc
);
for (int t = 0; t < numAudioChannels; t++)
{
assetWriterAudioInput[t] = [AVAssetWriterInput assetWriterInputWithMediaType:AVMediaTypeAudio outputSettings:audioSettings];
canAddAudioWriter = [assetWriter canAddInput:assetWriterAudioInput[t] ];
if (canAddAudioWriter)
{
assetWriterAudioInput[t].expectsMediaDataInRealTime = YES; //true;
[assetWriter addInput:assetWriterAudioInput[t] ];
}
}
CMFormatDescriptionRef myFormatDesc = assetWriterAudioInput[0].sourceFormatHint;
NSString* medType = [assetWriterAudioInput[0] mediaType];
}
if(canAddVideoWriter)
{
// tell the asset writer to expect media in real time.
assetWriterInputVideo.expectsMediaDataInRealTime = YES; //true;
// add the Input(s)
[assetWriter addInput:assetWriterInputVideo];
// Start writing the frames..
BOOL success = true;
success = [assetWriter startWriting];
CMTime startTime = CMTimeMake(0, fpsRate);
[assetWriter startSessionAtSourceTime:kCMTimeZero];
// [assetWriter startSessionAtSourceTime:startTime];
if (success)
{
startOurVideoCaptureProcess();
// **** possible enhancement is to use a pixelBufferPool to manage multiple buffers at once...
CVPixelBufferRef buffer = NULL;
int kRecordingFPS = fpsRate;
bool frameAdded = false;
unsigned int bufferID;
for( int i = 0; i < numFramesToCapture; i++)
{
printf("\n");
buffer = pixelBufferFromCard(bufferID, width, height, memFmt); // This function to get a CVBufferREf From our device, as well as getting the Audio data
while(!adaptor.assetWriterInput.readyForMoreMediaData)
{
printf(" readyForMoreMediaData FAILED \n");
}
if (buffer)
{
// Add video
printf("appending Frame %d ", i);
CMTime frameTime = CMTimeMake(i, kRecordingFPS);
frameAdded = [adaptor appendPixelBuffer:buffer withPresentationTime:frameTime];
if (frameAdded)
printf("VideoAdded.....\n ");
// Add Audio
{
// Do some Processing on the captured data to extract the interleaved Audio Samples for each channel
struct hanc_decode_struct decode;
DecodeHancFrameEx(gBFHancBuffer, decode);
int nAudioSamplesCaptured = 0;
if(decode.no_audio_samples > 0)
{
printf("completed deCodeHancEX, found %d samples \n", ( decode.no_audio_samples / numAudioChannels) );
nAudioSamplesCaptured = decode.no_audio_samples / numAudioChannels;
}
CMTime audioTimeStamp = CMTimeMake(nAudioSamplesWritten, 480000); // (Samples Written) / sampleRate for audio
// This function repacks the Audio from interleaved PCM data a vector of individual array of Audio data
RepackDecodedHancAudio((void*)pAudioSamples, numAudioChannels, nAudioSamplesCaptured, vecOfNonInterleavedAudioSamplesPtrs);
for (int t = 0; t < numAudioChannels; t++)
{
CMBlockBufferRef blockBuf = NULL; // *********** MUST release these AFTER adding the samples to the assetWriter...
CMSampleBufferRef cmBuf = NULL;
int sizeOfSamplesInBytes = nAudioSamplesCaptured * 2; // always 16bit memory samples...
// Create sample Block buffer for adding to the audio input.
status = CMBlockBufferCreateWithMemoryBlock(kCFAllocatorDefault,
(void*)vecOfNonInterleavedAudioSamplesPtrs[t],
sizeOfSamplesInBytes,
kCFAllocatorNull,
NULL,
0,
sizeOfSamplesInBytes,
0,
&blockBuf);
if (status != noErr)
NSLog(#"CMBlockBufferCreateWithMemoryBlock error");
status = CMAudioSampleBufferCreateWithPacketDescriptions(kCFAllocatorDefault,
blockBuf,
TRUE,
0,
NULL,
audioFormatDesc,
nAudioSamplesCaptured,
audioTimeStamp,
NULL,
&cmBuf);
if (status != noErr)
NSLog(#"CMSampleBufferCreate error");
// leys check if the CMSampleBuf is valid
bool bValid = CMSampleBufferIsValid(cmBuf);
// examine this values for debugging info....
CMTime cmTimeSampleDuration = CMSampleBufferGetDuration(cmBuf);
CMTime cmTimePresentationTime = CMSampleBufferGetPresentationTimeStamp(cmBuf);
if (status != noErr)
NSLog(#"Invalid Buffer found!!! possible CMSampleBufferCreate error?");
if(!assetWriterAudioInput[t].readyForMoreMediaData)
printf(" readyForMoreMediaData FAILED - Had to Drop a frame\n");
else
{
if(assetWriter.status == AVAssetWriterStatusWriting)
{
BOOL r = YES;
r = [assetWriterAudioInput[t] appendSampleBuffer:cmBuf];
if (!r)
{
NSLog(#"appendSampleBuffer error");
}
else
success = true;
}
else
printf("AssetWriter Not ready???!? \n");
}
if (cmBuf)
{
CFRelease(cmBuf);
cmBuf = 0;
}
if(blockBuf)
{
CFRelease(blockBuf);
blockBuf = 0;
}
}
nAudioSamplesWritten = nAudioSamplesWritten + nAudioSamplesCaptured;
}
if(success)
{
printf("Audio tracks Added..");
}
else
{
NSError* nsERR = [assetWriter error];
printf("Problem Adding Audio tracks / samples");
}
printf("Success \n");
}
if (buffer)
{
CVBufferRelease(buffer);
}
}
}
AVAssetWriterStatus sta = [assetWriter status];
CMTime endTime = CMTimeMake((numFramesToCapture-1), fpsRate);
if (audioFormatDesc)
{
CFRelease(audioFormatDesc);
audioFormatDesc = 0;
}
// Finish the session
StopVideoCaptureProcess();
[assetWriterInputVideo markAsFinished];
for (int t = 0; t < numAudioChannels; t++)
{
[assetWriterAudioInput[t] markAsFinished];
}
[assetWriter endSessionAtSourceTime:endTime];
bool finishedSuccessfully = [assetWriter finishWriting];
if (finishedSuccessfully)
NSLog(#"Writing file ended successfully \n");
else
{
NSLog(#"Writing file ended WITH ERRORS...");
sta = [assetWriter status];
if (sta != AVAssetWriterStatusCompleted)
{
NSError* nsERR = [assetWriter error];
printf("investoigating the error \n");
}
}
}
else
{
NSLog(#"Unable to Add the InputVideo Asset Writer to the AssetWriter, file will not be written - Exiting");
}
if (audioFormatDesc)
CFRelease(audioFormatDesc);
}
for (int i = 0; i < 16; i++)
{
if (vecOfNonInterleavedAudioSamplesPtrs[i])
{
bfFree(2002 * sizeof(unsigned short), vecOfNonInterleavedAudioSamplesPtrs[i]);
vecOfNonInterleavedAudioSamplesPtrs[i] = nullptr;
}
}
}
else
{
NSLog(#"Unable to find a valid input signal - Exiting");
}
if (pAudioSamples)
delete pAudioSamples;
}
}
return 0;
}
It's a very basic sample that connects to some special hardware ( code for that is left out)
It grabs frames of video and audio, and then there is the processing for the Audio to go from interleaved PCM to the individual Array's of PCM data for each track
and then each buffer is added to the appropriate track, be it video or audio...
Lastly the AvAsset stuff is finished and closed and i exit and clean up.
Any help will be most appreciated,
Cheers,
James

Well i finally found a working solution for this problem.
The solution comes in 2 parts:
I moved from using CMAudioSampleBufferCreateWithPacketDescriptions
to using CMSampleBufferCreate(..) and the appropriate arguments to that function call.
Initially when experiementing with CMSampleBufferCreate i was mis-using some of the arguments and it was giving me the same results as i initially outlined here, but with careful examination of the values i was passing for the CMSampleTimingInfo struct - specifically the duration part, i eventually got everything working correctly!!
So it appears that i was creating the CMBlockBufferRef correctly, but i needed to take more care when using this to create the CMSampleBufRef that i was passing to the AVAssetWriterInput!
Hope this helps someone else, as it was a nasty one for me to solve!
James

Related

Where to retrieve audio file? -- Arduino - Photon project

I have just started with electronics, and doing a project using the Spark Photon, which is based on Arduino. The project website is here: http://hackster.io/middleca/sending-sound-over-the-internet
I uploaded the following two files (.ino and .js) to the Photon, which should then capture and transmit sound (directly I assume). I expected a test.wav would be created. However, where should I find this file so I can check if everything worked?
main.ino file:
#define MICROPHONE_PIN A5
#define AUDIO_BUFFER_MAX 8192
int audioStartIdx = 0, audioEndIdx = 0;
uint16_t audioBuffer[AUDIO_BUFFER_MAX];
uint16_t txBuffer[AUDIO_BUFFER_MAX];
// version without timers
unsigned long lastRead = micros();
char myIpAddress[24];
TCPClient audioClient;
TCPClient checkClient;
TCPServer audioServer = TCPServer(3443);
void setup() {
Serial.begin(115200);
pinMode(MICROPHONE_PIN, INPUT);
// so we know where to connect, try:
// particle get MY_DEVICE_NAME ipAddress
Spark.variable("ipAddress", myIpAddress, STRING);
IPAddress myIp = WiFi.localIP();
sprintf(myIpAddress, "%d.%d.%d.%d", myIp[0], myIp[1], myIp[2], myIp[3]);
// 1/8000th of a second is 125 microseconds
audioServer.begin();
lastRead = micros();
}
void loop() {
checkClient = audioServer.available();
if (checkClient.connected()) {
audioClient = checkClient;
}
//listen for 100ms, taking a sample every 125us,
//and then send that chunk over the network.
listenAndSend(100);
}
void listenAndSend(int delay) {
unsigned long startedListening = millis();
while ((millis() - startedListening) < delay) {
unsigned long time = micros();
if (lastRead > time) {
// time wrapped?
//lets just skip a beat for now, whatever.
lastRead = time;
}
//125 microseconds is 1/8000th of a second
if ((time - lastRead) > 125) {
lastRead = time;
readMic();
}
}
sendAudio();
}
// Callback for Timer 1
void readMic(void) {
uint16_t value = analogRead(MICROPHONE_PIN);
if (audioEndIdx >= AUDIO_BUFFER_MAX) {
audioEndIdx = 0;
}
audioBuffer[audioEndIdx++] = value;
}
void copyAudio(uint16_t *bufferPtr) {
//if end is after start, read from start->end
//if end is before start, then we wrapped, read from start->max, 0->end
int endSnapshotIdx = audioEndIdx;
bool wrapped = endSnapshotIdx < audioStartIdx;
int endIdx = (wrapped) ? AUDIO_BUFFER_MAX : endSnapshotIdx;
int c = 0;
for(int i=audioStartIdx;i<endIdx;i++) {
// do a thing
bufferPtr[c++] = audioBuffer[i];
}
if (wrapped) {
//we have extra
for(int i=0;i<endSnapshotIdx;i++) {
// do more of a thing.
bufferPtr[c++] = audioBuffer[i];
}
}
//and we're done.
audioStartIdx = audioEndIdx;
if (c < AUDIO_BUFFER_MAX) {
bufferPtr[c] = -1;
}
}
// Callback for Timer 1
void sendAudio(void) {
copyAudio(txBuffer);
int i=0;
uint16_t val = 0;
if (audioClient.connected()) {
write_socket(audioClient, txBuffer);
}
else {
while( (val = txBuffer[i++]) < 65535 ) {
Serial.print(val);
Serial.print(',');
}
Serial.println("DONE");
}
}
// an audio sample is 16bit, we need to convert it to bytes for sending over the network
void write_socket(TCPClient socket, uint16_t *buffer) {
int i=0;
uint16_t val = 0;
int tcpIdx = 0;
uint8_t tcpBuffer[1024];
while( (val = buffer[i++]) < 65535 ) {
if ((tcpIdx+1) >= 1024) {
socket.write(tcpBuffer, tcpIdx);
tcpIdx = 0;
}
tcpBuffer[tcpIdx] = val & 0xff;
tcpBuffer[tcpIdx+1] = (val >> 8);
tcpIdx += 2;
}
// any leftovers?
if (tcpIdx > 0) {
socket.write(tcpBuffer, tcpIdx);
}
}
and the waveRecorder.js file:
// make sure you have Node.js Installed!
// Get the IP address of your photon, and put it here:
// CLI command to get your photon's IP address
//
// particle get MY_DEVICE_NAME ipAddress
// Put your IP here!
var settings = {
ip: "192.168.0.54",
port: 3443
};
/**
* Created by middleca on 7/18/15.
*/
//based on a sample from here
// http://stackoverflow.com/questions/19548755/nodejs-write-binary-data-into-writablestream-with-buffer
var fs = require("fs");
var samplesLength = 1000;
var sampleRate = 8000;
var outStream = fs.createWriteStream("test.wav");
var writeHeader = function() {
var b = new Buffer(1024);
b.write('RIFF', 0);
/* file length */
b.writeUInt32LE(32 + samplesLength * 2, 4);
//b.writeUint32LE(0, 4);
b.write('WAVE', 8);
/* format chunk identifier */
b.write('fmt ', 12);
/* format chunk length */
b.writeUInt32LE(16, 16);
/* sample format (raw) */
b.writeUInt16LE(1, 20);
/* channel count */
b.writeUInt16LE(1, 22);
/* sample rate */
b.writeUInt32LE(sampleRate, 24);
/* byte rate (sample rate * block align) */
b.writeUInt32LE(sampleRate * 2, 28);
/* block align (channel count * bytes per sample) */
b.writeUInt16LE(2, 32);
/* bits per sample */
b.writeUInt16LE(16, 34);
/* data chunk identifier */
b.write('data', 36);
/* data chunk length */
//b.writeUInt32LE(40, samplesLength * 2);
b.writeUInt32LE(0, 40);
outStream.write(b.slice(0, 50));
};
writeHeader(outStream);
var net = require('net');
console.log("connecting...");
client = net.connect(settings.port, settings.ip, function () {
client.setNoDelay(true);
client.on("data", function (data) {
try {
console.log("GOT DATA");
outStream.write(data);
//outStream.flush();
console.log("got chunk of " + data.toString('hex'));
}
catch (ex) {
console.error("Er!" + ex);
}
});
});
setTimeout(function() {
console.log('recorded for 10 seconds');
client.end();
outStream.end();
process.exit(0);
}, 10 * 1000);
Thieme! Such a beginner's question... SO unworthy!
Anyway, I will iron my heart and tell you the answer.
First of all, you misunderstood: the .ino file should go to the Photon and the waveRecorder.js file should be stored on your computer (or server) and called whenever you want to retrieve the audio. As you can read in the code, the .ino file makes sure that every millisecond it will check if something wants to connect, and if so, it will stream the sound to the wav.file stored in the same location as your waveRecorder.js file. "Something wants to connect" happens when you launch waveRecorder.js. Make sure you have node installed.
So, to sum it up:
Download the two files (main.ino and waveRecorder.js) to your computer in a folder ../xx/folderName
Then configure the IPAddress in both files using your photon's IPAddress
Upload main.ino to the photon (type 'particle flash abcdefgh123456578 "xx/../folderName/main.ino"' in the terminal)
Then run waveRecorder.js by typing 'node "xx/../folderName/waveRecorder.js"' in your terminal.
That should do it.. Even I got it working :)

vorbis_analysis generates access violation

I'm trying to create an .ogg file, but even the example code presented generates an Access Violation when calling vorbis_analysis().
I'm using a simplified version of this encoding Example. I have tried the full example as it is, but I get the same error at the same place.
The code below is the example simplified by filling the encoding buffer with a constant instead of a wav file. The hFile is a TStreamFile instance created elsewhere.
vorbis_info vi;
vorbis_dsp_state vd;
vorbis_comment vc;
vorbis_block vb;
ogg_stream_state os;
ogg_page og;
ogg_packet op;
ogg_packet header;
ogg_packet header_comm;
ogg_packet header_code;
int res;
int len = 0;
int eos = 0;
int loop = 0;
vorbis_info_init(&vi);
res = vorbis_encode_init_vbr(&vi,2,44100,0.4f);
res = vorbis_encode_setup_init(&vi);
vorbis_comment_init(&vc);
vorbis_comment_add_tag(&vc,"TITLE","Silent noise");
res = vorbis_analysis_init(&vd,&vi);
res = vorbis_block_init(&vd,&vb);
srand(time(NULL));
res = ogg_stream_init(&os,rand());
res = vorbis_analysis_headerout(&vd,&vc,&header,&header_comm,&header_code);
res = ogg_stream_packetin(&os,&header);
res = ogg_stream_packetin(&os,&header_comm);
res = ogg_stream_packetin(&os,&header_code);
/* This ensures the actual
* audio data will start on a new page, as per spec
*/
while(ogg_stream_flush(&os,&og)) {
hFile->Write(og.header,og.header_len);
hFile->Write(og.body, og.body_len );
}
while(!eos) {
float **Buffer = vorbis_analysis_buffer(&vd,1024);
if(loop<10) {
for(int n=0; n<1024; n++) {
Buffer[0][n] = 1.0f;
Buffer[1][n] = 1.0f;
}
res = vorbis_analysis_wrote(&vd,1024);
loop++;
} else {
res = vorbis_analysis_wrote(&vd,0);
eos = true;
}
// Enough data?
while(vorbis_analysis_blockout(&vd,&vb) == 1) {
res = vorbis_analysis(&vb,&op); // <---- Access Violation
res = vorbis_bitrate_addblock(&vb);
while(vorbis_bitrate_flushpacket(&vd,&op)) {
/* weld the packet into the bitstream */
res = ogg_stream_packetin(&os,&op);
/* write out pages (if any) */
while(!eos){
if(ogg_stream_pageout(&os,&og) == 0) {
break;
}
hFile->Write(og.header,og.header_len);
hFile->Write(og.body, og.body_len );
/* this could be set above, but for illustrative purposes, I do
it here (to show that vorbis does know where the stream ends) */
if(ogg_page_eos(&og)) {
eos=1;
}
}
}
}
}
res = ogg_stream_clear(&os);
res = vorbis_block_clear(&vb);
vorbis_dsp_clear(&vd);
vorbis_comment_clear(&vc);
vorbis_info_clear(&vi);
The first part runs fine, the header is created and saved to the stream. Then I just fill the buffer with 1.0 floats for test purposes.
When there is enough data available the call to vorbis_analysis always generate Access Violation at x write of address x
The variable res always indicate success all the way down to the access violation.
I'm using static linked libogg v1.3.2 and libvorbis 1.3.5

Rotate a image in c++

Hi I am very new to c++.
Image im(L"C:\\Temp\\SnapShotOutput.jpg");
im.RotateFlip(Rotate90FlipNone);
im.Save("SampleImage_rotated.jpg");
I am trying to above code to rotate a image and save...
It wont work .compile fail at the 3rd line
'Gdiplus::Image::Save' : no overloaded function takes 1 arguments
it gives the above error.
can anybody help me.
You should set other parameters too. Code is from here.
Image image(L"C:\\Temp\\SnapShotOutput.jpg");
image.RotateFlip(Rotate90FlipNone);
// Save the altered image as PNG
CLSID pngClsid;
GetEncoderClsid(L"image/png", &pngClsid);
image.Save(L"SampleImage_rotated.png", &pngClsid, NULL);
// Save the altered image as JPG
CLSID jpegClsid;
GetEncoderClsid(L"image/jpeg", &jpegClsid);
image.Save(L"SampleImage_rotated.jpg", &jpegClsid, NULL);
The GetEncoderClsid function is defined here:
int GetEncoderClsid(const WCHAR* format, CLSID* pClsid)
{
UINT num = 0; // number of image encoders
UINT size = 0; // size of the image encoder array in bytes
ImageCodecInfo* pImageCodecInfo = NULL;
GetImageEncodersSize(&num, &size);
if(size == 0)
return -1; // Failure
pImageCodecInfo = (ImageCodecInfo*)(malloc(size));
if(pImageCodecInfo == NULL)
return -1; // Failure
GetImageEncoders(num, size, pImageCodecInfo);
for(UINT j = 0; j < num; ++j)
{
if( wcscmp(pImageCodecInfo[j].MimeType, format) == 0 )
{
*pClsid = pImageCodecInfo[j].Clsid;
free(pImageCodecInfo);
return j; // Success
}
}
free(pImageCodecInfo);
return -1; // Failure
}

Sample rate & format conversion with LibAV API (libavresample)

I'm writing a code which will merge multiple audios (with different formats) and create a single audio. When i set the encoder sample_rate and sample_fmt same with the input videos i have no problem merging the audios. However as obvious, all of the input audio formats are not same with the output format, so i have to do format conversion. I tried to use "avresample" for this purpose but could not manage to encode the output frames when sample_rate and sample_fmt are different for input&output.
It might be done manually by hand (by sample dropping, interpolation etc.), but since libav provides a conversion api i think this can (and may be should for tidyness) be done automatically.
Here is how i set encoder and resampling context params:
AVCodecContext* avAudioEncoder = outputAudioStream->codec;
AVCodec * audioEncoder = avcodec_find_encoder(AV_CODEC_ID_MP3);
avcodec_get_context_defaults3(avAudioEncoder, audioEncoder);
avAudioEncoder->sample_fmt = AV_SAMPLE_FMT_S16P;
avAudioEncoder->sample_rate = 48000;
avAudioEncoder->channels = 2;
avAudioEncoder->time_base.num = 1;
avAudioEncoder->time_base.den = 48000;
avAudioEncoder->strict_std_compliance = FF_COMPLIANCE_EXPERIMENTAL;
if (outputAVFormat->oformat->flags & AVFMT_GLOBALHEADER)
{
avAudioEncoder->flags |= CODEC_FLAG_GLOBAL_HEADER;
}
avcodec_open2(avAudioEncoder, audioEncoder, nullptr);
std::shared_ptr<AVAudioResampleContext> avAudioResampleContext(avresample_alloc_context(), [](AVAudioResampleContext * avARC){avresample_close(avARC), avresample_free(&avARC); });
av_opt_set_int(avAudioResampleContext.get(), "in_channel_layout", 2, 0);
av_opt_set_int(avAudioResampleContext.get(), "in_sample_rate", 44100, 0);
av_opt_set_int(avAudioResampleContext.get(), "in_sample_fmt", AV_SAMPLE_FMT_S16P, 0);
av_opt_set_int(avAudioResampleContext.get(), "out_channel_layout", avAudioEncoder->channels, 0);
av_opt_set_int(avAudioResampleContext.get(), "out_sample_rate", avAudioEncoder->sample_rate, 0);
av_opt_set_int(avAudioResampleContext.get(), "out_sample_fmt", avAudioEncoder->sample_fmt, 0);
And here is how i read & encode the frames
...
int result = avcodec_decode_audio4(avAudioDecoder.get(), audioFrame.get(), &isFrameAvailable, &decodingPacket);
...
if (isFrameAvailable)
{
decodingPacket.size -= result;
decodingPacket.data += result;
encodeAudioFrame->format = outputAudioStream->codec->sample_fmt;
encodeAudioFrame->channel_layout = outputAudioStream->codec->channel_layout;
auto available = avresample_available(avAudioResampleContext.get());
auto delay = avresample_get_delay(avAudioResampleContext.get());
encodeAudioFrame->nb_samples = available + av_rescale_rnd( delay + audioFrame->nb_samples, avAudioEncoder->sample_rate, audioStream->codec->sample_rate, AV_ROUND_ZERO);
int linesize;
av_samples_alloc(encodeAudioFrame->data, &linesize, avAudioEncoder->channels, encodeAudioFrame->nb_samples, avAudioEncoder->sample_fmt, 1);
encodeAudioFrame->linesize[0] = linesize;
avresample_convert(avAudioResampleContext.get(), nullptr, encodeAudioFrame->linesize[0], encodeAudioFrame->nb_samples, &audioFrame->data[0], audioFrame->linesize[0], audioFrame->nb_samples*outputAudioStream->codec->channels);
std::shared_ptr<AVPacket> outPacket(new AVPacket, [](AVPacket* p){ av_free_packet(p); delete p; });
av_init_packet(outPacket.get());
outPacket->data = nullptr;
outPacket->size = 0;
while (avresample_available(avAudioResampleContext.get()) >= encodeAudioFrame->nb_samples)
{
avresample_read(avAudioResampleContext.get(), &encodeAudioFrame->data[0], encodeAudioFrame->nb_samples*outputAudioStream->codec->channels);
encodeAudioFrame->pts = av_rescale_q(++encodedAudioPts, outputAudioStream->codec->time_base, outputAudioStream->time_base);
encodeAudioFrame->pts *= avAudioEncoder->frame_size;
...
auto ret = avcodec_encode_audio2(avAudioEncoder, outPacketPtr, encodeAudioFramePtr, &got_output);
...
}
It seems i can't use avresample properly, but i could not figure out how to solve this problem. Any help will be appreciated.

Duration of an amr audio file

i want to find the duration of an audio file of type "amr" without converting it to other audio formats
with any way?
AK
I have coded the following in objective-C to get the duration of a movie. This can similarly be used to get the duration of audio too:
-(double)durationOfMovieAtPath:(NSString*)inMoviePath
{
double durationToReturn = -1;
NSFileManager *fm = [NSFileManager defaultManager];
if ([fm fileExistsAtPath:inMoviePath])
{
av_register_all();
AVFormatContext *inMovieFormat = NULL;
inMovieFormat = avformat_alloc_context();
int errorCode = av_open_input_file(&inMovieFormat, [inMoviePath UTF8String], NULL, 0, NULL);
//double durationToReturn = (double)inMovieFormat->duration / AV_TIME_BASE;
if (0==errorCode)
{
// only on success
int numberOfStreams = inMovieFormat->nb_streams;
AVStream *videoStream = NULL;
for (int i=0; i<numberOfStreams; i++)
{
AVStream *st = inMovieFormat->streams[i];
if (st->codec->codec_type == CODEC_TYPE_VIDEO)
{
videoStream = st;
break;
}
}
double divideFactor;
// The duraion in AVStream is set in accordance with the time_base of AVStream, so we need to fetch back the duration using this factor
divideFactor = (double)1/rationalToDouble(videoStream->time_base);
if (NULL!=videoStream)
durationToReturn = (double)videoStream->duration / divideFactor;
//DEBUGLOG (#"Duration of movie at path: %# = %0.3f", inMoviePath, durationToReturn);
}
else
{
DEBUGLOG (#"avformat_alloc_context error code = %d", errorCode);
}
if (nil!=inMovieFormat)
{
av_close_input_file(inMovieFormat);
//av_free(inMovieFormat);
}
}
return durationToReturn;
}
Change the CODEC_TYPE_VIDEO to CODEC_TYPE_AUDIO and I think it should work for you.

Resources