diff --git a/app/src/main/cpp/CMakeLists.txt b/app/src/main/cpp/CMakeLists.txt index 27cc652f..96b4c972 100644 --- a/app/src/main/cpp/CMakeLists.txt +++ b/app/src/main/cpp/CMakeLists.txt @@ -122,6 +122,7 @@ target_link_libraries( # Specifies the target library. oboe::oboe libsndfile libopusenc + libap4 libopus libmp3lame libfaac diff --git a/app/src/main/cpp/Engine.cpp b/app/src/main/cpp/Engine.cpp index 99dd4b8d..bb3cd484 100644 --- a/app/src/main/cpp/Engine.cpp +++ b/app/src/main/cpp/Engine.cpp @@ -87,6 +87,7 @@ bool Engine::setEffectOn(bool isOn) { } */ + meter->lastRecordedFileName = fileWriter->filename; meter->enable(); meter->start(); meter->faacInit(mSampleRate, bufferSizeInFrames); diff --git a/app/src/main/cpp/MP4.cpp b/app/src/main/cpp/MP4.cpp index 7085edad..e054c4f6 100644 --- a/app/src/main/cpp/MP4.cpp +++ b/app/src/main/cpp/MP4.cpp @@ -12,85 +12,140 @@ MP4::MakeDsi(unsigned int sampling_frequency_index, unsigned int channel_configu dsi[1] = ((sampling_frequency_index&1)<<7) | (channel_configuration<<3); } -void MP4::openFile (std::string _filename) { - filename = _filename ; - result = AP4_FileByteStream::Create(filename.c_str(), AP4_FileByteStream::STREAM_MODE_WRITE, output); +void MP4::aacToMP4 () { + fclose(tmpfile); + AP4_Result result; + AP4_ByteStream* input = NULL; + result = AP4_FileByteStream::Create(tmp.c_str(), AP4_FileByteStream::STREAM_MODE_READ, input); if (AP4_FAILED(result)) { - LOGE("ERROR: cannot open output (%s) %d\n", filename.c_str(), result); + LOGE("ERROR: cannot open input (%s) %d\n", tmp.c_str(), result); return ; } - AP4_AacFrame frame; - result = parser.FindFrame(frame); - if (AP4_SUCCEEDED(result)) { - LOGI("AAC frame [%06d]: size = %d, %d kHz, %d ch\n", - sample_count, - frame.m_Info.m_FrameLength, - frame.m_Info.m_SamplingFrequency, - frame.m_Info.m_ChannelConfiguration); - } else { - HERE LOGE("[mp4] failed to find frame"); - return; + // open the output + AP4_ByteStream* output = NULL; + result = AP4_FileByteStream::Create(lastRecordedFile.c_str(), AP4_FileByteStream::STREAM_MODE_WRITE, output); + if (AP4_FAILED(result)) { + LOGE("ERROR: cannot open output (%s) %d\n",lastRecordedFile.c_str(), result); + return ; } - initialized = true; - sample_table = new AP4_SyntheticSampleTable(); - AP4_DataBuffer dsi; - unsigned char aac_dsi[2]; - MakeDsi(frame.m_Info.m_SamplingFrequencyIndex, frame.m_Info.m_ChannelConfiguration, aac_dsi); - dsi.SetData(aac_dsi, 2); - - AP4_MpegAudioSampleDescription* sample_description = - new AP4_MpegAudioSampleDescription( - AP4_OTI_MPEG4_AUDIO, // object type - frame.m_Info.m_SamplingFrequency, - 16, // sample size - frame.m_Info.m_ChannelConfiguration, - &dsi, // decoder info - 6144, // buffer size - 256000, // max bitrate - 128000); // average bitrate - sample_description_index = sample_table->GetSampleDescriptionCount(); - sample_table->AddSampleDescription(sample_description); - sample_rate = frame.m_Info.m_SamplingFrequency; - - AP4_MemoryByteStream* sample_data = new AP4_MemoryByteStream(frame.m_Info.m_FrameLength); - frame.m_Source->ReadBytes(sample_data->UseData(), frame.m_Info.m_FrameLength); - sample_table->AddSample(*sample_data, 0, frame.m_Info.m_FrameLength, 1024, sample_description_index, 0, 0, true); - sample_data->Release(); - sample_count++; - - movie = new AP4_Movie(); - track = new AP4_Track(AP4_Track::TYPE_AUDIO, - sample_table, - 0, // track id - sample_rate, // movie time scale - sample_count*1024, // track duration - sample_rate, // media time scale - sample_count*1024, // media duration - "eng", // language - 0, 0); // width, height + // create a sample table + AP4_SyntheticSampleTable* sample_table = new AP4_SyntheticSampleTable(); + + // create an ADTS parser + AP4_AdtsParser parser; + bool initialized = false; + unsigned int sample_description_index = 0; + + // read from the input, feed, and get AAC frames + AP4_UI32 sample_rate = 0; + AP4_Cardinal sample_count = 0; + bool eos = false; + for(;;) { + // try to get a frame + AP4_AacFrame frame; + result = parser.FindFrame(frame); + if (AP4_SUCCEEDED(result)) { + LOGD("AAC frame [%06d]: size = %d, %d kHz, %d ch\n", + sample_count, + frame.m_Info.m_FrameLength, + frame.m_Info.m_SamplingFrequency, + frame.m_Info.m_ChannelConfiguration); + if (!initialized) { + initialized = true; + + // create a sample description for our samples + AP4_DataBuffer dsi; + unsigned char aac_dsi[2]; + MakeDsi(frame.m_Info.m_SamplingFrequencyIndex, frame.m_Info.m_ChannelConfiguration, aac_dsi); + dsi.SetData(aac_dsi, 2); + AP4_MpegAudioSampleDescription* sample_description = + new AP4_MpegAudioSampleDescription( + AP4_OTI_MPEG4_AUDIO, // object type + frame.m_Info.m_SamplingFrequency, + 16, // sample size + frame.m_Info.m_ChannelConfiguration, + &dsi, // decoder info + 6144, // buffer size + 128000, // max bitrate + 128000); // average bitrate + sample_description_index = sample_table->GetSampleDescriptionCount(); + sample_table->AddSampleDescription(sample_description); + sample_rate = frame.m_Info.m_SamplingFrequency; + } + + AP4_MemoryByteStream* sample_data = new AP4_MemoryByteStream(frame.m_Info.m_FrameLength); + frame.m_Source->ReadBytes(sample_data->UseData(), frame.m_Info.m_FrameLength); + sample_table->AddSample(*sample_data, 0, frame.m_Info.m_FrameLength, 1024, sample_description_index, 0, 0, true); + sample_data->Release(); + sample_count++; + } else if (!eos) { + // read some data and feed the parser + AP4_UI08 input_buffer[4096]; + AP4_Size to_read = parser.GetBytesFree(); + if (to_read) { + AP4_Size bytes_read = 0; + if (to_read > sizeof(input_buffer)) to_read = sizeof(input_buffer); + result = input->ReadPartial(input_buffer, to_read, bytes_read); + if (AP4_SUCCEEDED(result)) { + AP4_Size to_feed = bytes_read; + result = parser.Feed(input_buffer, &to_feed); + if (AP4_FAILED(result)) { + LOGE("ERROR: parser.Feed() failed (%d)\n", result); + return; + } + } else { + if (result == AP4_ERROR_EOS) { + eos = true; + parser.Feed(NULL, 0, true); + } + } + } + } else { + LOGE ("[mp4] unable to find a frame or do anything !!!"); + abort(); + break; + } + } + // create a movie + AP4_Movie* movie = new AP4_Movie(); + + // create an audio track + AP4_Track* track = new AP4_Track(AP4_Track::TYPE_AUDIO, + sample_table, + 0, // track id + sample_rate, // movie time scale + sample_count*1024, // track duration + sample_rate, // media time scale + sample_count*1024, // media duration + "eng", // language + 0, 0); // width, height + + // add the track to the movie movie->AddTrack(track); - file = new AP4_File(movie); + // create a multimedia file + AP4_File* file = new AP4_File(movie); + + // set the file type AP4_UI32 compatible_brands[2] = { AP4_FILE_BRAND_ISOM, AP4_FILE_BRAND_MP42 }; - file->SetFileType(AP4_FILE_BRAND_M4A_, 0, compatible_brands, 2); -} + // write the file to the output + AP4_FileWriter::Write(*file, *output); -void MP4::writeFile (unsigned char * data) { - -} - -void MP4::closeFile () { delete file; input->Release(); output->Release(); +} + +void MP4::write (unsigned char * data, int nframes) { + fwrite (data, nframes, 0, tmpfile); } \ No newline at end of file diff --git a/app/src/main/cpp/MP4.h b/app/src/main/cpp/MP4.h index a229f41a..5442e84f 100644 --- a/app/src/main/cpp/MP4.h +++ b/app/src/main/cpp/MP4.h @@ -5,36 +5,35 @@ #ifndef AMP_RACK_MP4_H #define AMP_RACK_MP4_H +#include #include #include "bento4/Ap4.h" #include "bento4/Ap4AdtsParser.h" #include "logging_macros.h" class MP4 { - std::string filename ; - AP4_Result result; - AP4_ByteStream* input = NULL; - AP4_ByteStream* output = NULL; - AP4_SyntheticSampleTable* sample_table; - AP4_AdtsParser parser; - bool initialized = false; - unsigned int sample_description_index = 0; - - // read from the input, feed, and get AAC frames - AP4_UI32 sample_rate = 0; - AP4_Cardinal sample_count = 0; - bool eos = false; - - AP4_Movie* movie = nullptr ; - AP4_Track* track = nullptr ; - AP4_File* file = nullptr ; - - void openFile(std::string _filename); +public: + std::string lastRecordedFile, tmp ; + FILE * tmpfile = noll; + + MP4(std::string _filename) { + lastRecordedFile = _filename ; + lastRecordedFile = "/sdcard/Android/data/com.shajikhan.ladspa.amprack/files/Music/test.mp4"; + tmp = lastRecordedFile + ".aac" ; + tmpfile = fopen (tmp.c_str(), "wb"); + LOGD("[mp4] opened tmp file %s", tmp.c_str()); + } + + ~MP4() { +// remove (tmp.c_str()); + } void MakeDsi(unsigned int sampling_frequency_index, unsigned int channel_configuration, unsigned char *dsi); - void writeFile(unsigned char *data); + void aacToMP4(); + + void write(unsigned char *data, int nframes); }; diff --git a/app/src/main/cpp/Meter.cpp b/app/src/main/cpp/Meter.cpp index b0bd0eff..5fe5023d 100644 --- a/app/src/main/cpp/Meter.cpp +++ b/app/src/main/cpp/Meter.cpp @@ -7,7 +7,9 @@ #define TUNER_ARRAY_SIZE 4096 -jchar * Meter::audioToVideoBytes = NULL ; +MP4 * Meter::mp4 ; + +unsigned char * Meter::audioToVideoBytes = NULL ; faacEncHandle Meter::faacEncHandle = nullptr; jfloatArray Meter::jfloatArray1 ; int Meter::jfloatArray1_index = 0 ; @@ -147,7 +149,7 @@ int Meter::updateMeterOutput (AudioBuffer * buffer) { // this should never be more than this jfloatArray1 = envOutput->NewFloatArray(TUNER_ARRAY_SIZE); pushVideoSamples = envOutput->NewCharArray(TUNER_ARRAY_SIZE); - audioToVideoBytes = (jchar *) malloc(sizeof(jchar) * TUNER_ARRAY_SIZE); + audioToVideoBytes = (unsigned char *) malloc(sizeof(unsigned char) * TUNER_ARRAY_SIZE); jfloatArray1_index = 0 ; return 0 ; } else { @@ -161,6 +163,13 @@ int Meter::updateMeterOutput (AudioBuffer * buffer) { jfloatArray1_index += samples; } + // mp4 muxer test + int bytesWritten = faacEncode(data, samples, audioToVideoBytes, TUNER_ARRAY_SIZE); + if (bytesWritten >= 0) { + mp4 -> write (audioToVideoBytes, bytesWritten); + } + // end mp4 muxer test + /* if (videoRecording) { int bytesWritten = faacEncode(data, samples, audioToVideoBytes, TUNER_ARRAY_SIZE); if (bytesWritten >= 0) { @@ -170,6 +179,7 @@ int Meter::updateMeterOutput (AudioBuffer * buffer) { bytesWritten); } } + */ } @@ -218,11 +228,14 @@ int Meter::updateMeterOutput (AudioBuffer * buffer) { void Meter::start () { engine_running = true ; + mp4 = new MP4 (lastRecordedFileName); } void Meter::stop () { IN engine_running = false ; + mp4 ->aacToMP4(); + delete mp4 ; /* we never detach envOutput = nullptr ; @@ -471,7 +484,7 @@ void Meter::faacConfig () { faacEncSetConfiguration(faacEncHandle, config); } -int Meter::faacEncode (float * data, int nframes, jchar *outputBuffer, +int Meter::faacEncode (float * data, int nframes, unsigned char *outputBuffer, unsigned int bufferSize) { int bytesWritten = faacEncEncode(faacEncHandle, (int32_t *) data, nframes, (unsigned char *) outputBuffer, bufferSize) ; if (bytesWritten < 0) { @@ -481,6 +494,6 @@ int Meter::faacEncode (float * data, int nframes, jchar *outputBuffer, // for (int i = 0 ; i < bytesWritten ; i ++) // LOGD("%c", outputBuffer [i]); // - LOGD("[faac] in %d: out: %d", nframes, bytesWritten); +// LOGD("[faac] in %d: out: %d", nframes, bytesWritten); return bytesWritten; } \ No newline at end of file diff --git a/app/src/main/cpp/Meter.h b/app/src/main/cpp/Meter.h index 5949cf09..0b504658 100644 --- a/app/src/main/cpp/Meter.h +++ b/app/src/main/cpp/Meter.h @@ -21,6 +21,7 @@ extern "C" { #endif #include "LockFreeQueue.h" #include "faac.h" +#include "MP4.h" //#include "FileWriter.h" JNIEnv* getEnv() ; @@ -60,6 +61,8 @@ class Meter { public: Meter(JavaVM *pVm); + std::string lastRecordedFileName ; + static MP4 * mp4 ; static bool tunerEnabled ; static jmethodID setMixerMeter ; static jclass mainActivity ; @@ -225,9 +228,9 @@ class Meter { void faacConfig(); - static int faacEncode(float * data, int nframes, jchar *outputBuffer, unsigned int bufferSize); + static int faacEncode(float * data, int nframes, unsigned char *outputBuffer, unsigned int bufferSize); - static jchar *audioToVideoBytes; + static unsigned char *audioToVideoBytes; }; #endif //AMP_RACK_METER_H diff --git a/app/src/main/cpp/logging_macros.h b/app/src/main/cpp/logging_macros.h index ade3757b..d1c8de4a 100644 --- a/app/src/main/cpp/logging_macros.h +++ b/app/src/main/cpp/logging_macros.h @@ -17,6 +17,7 @@ #ifndef __SAMPLE_ANDROID_DEBUG_H__ #define __SAMPLE_ANDROID_DEBUG_H__ #include +#include "utils.h" #if 1 #ifndef MODULE_NAME diff --git a/app/src/main/cpp/utils.h b/app/src/main/cpp/utils.h new file mode 100644 index 00000000..c462d28c --- /dev/null +++ b/app/src/main/cpp/utils.h @@ -0,0 +1,9 @@ +// +// Created by djshaji on 3/20/24. +// + +#ifndef AMP_RACK_UTILS_H +#define AMP_RACK_UTILS_H +#define noll nullptr + +#endif //AMP_RACK_UTILS_H