Skip to content

Commit

Permalink
Bento4 muxer
Browse files Browse the repository at this point in the history
  • Loading branch information
Shaji Khan committed Mar 20, 2024
1 parent 1a964da commit 3280833
Show file tree
Hide file tree
Showing 8 changed files with 168 additions and 86 deletions.
1 change: 1 addition & 0 deletions app/src/main/cpp/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,7 @@ target_link_libraries( # Specifies the target library.
oboe::oboe
libsndfile
libopusenc
libap4
libopus
libmp3lame
libfaac
Expand Down
1 change: 1 addition & 0 deletions app/src/main/cpp/Engine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ bool Engine::setEffectOn(bool isOn) {
}
*/

meter->lastRecordedFileName = fileWriter->filename;
meter->enable();
meter->start();
meter->faacInit(mSampleRate, bufferSizeInFrames);
Expand Down
175 changes: 115 additions & 60 deletions app/src/main/cpp/MP4.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
39 changes: 19 additions & 20 deletions app/src/main/cpp/MP4.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,36 +5,35 @@
#ifndef AMP_RACK_MP4_H
#define AMP_RACK_MP4_H

#include <stdlib.h>
#include <string>
#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);
};


Expand Down
21 changes: 17 additions & 4 deletions app/src/main/cpp/Meter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 ;
Expand Down Expand Up @@ -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 {
Expand All @@ -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) {
Expand All @@ -170,6 +179,7 @@ int Meter::updateMeterOutput (AudioBuffer * buffer) {
bytesWritten);
}
}
*/
}


Expand Down Expand Up @@ -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 ;
Expand Down Expand Up @@ -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) {
Expand All @@ -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;
}
7 changes: 5 additions & 2 deletions app/src/main/cpp/Meter.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ extern "C" {
#endif
#include "LockFreeQueue.h"
#include "faac.h"
#include "MP4.h"

//#include "FileWriter.h"
JNIEnv* getEnv() ;
Expand Down Expand Up @@ -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 ;
Expand Down Expand Up @@ -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
1 change: 1 addition & 0 deletions app/src/main/cpp/logging_macros.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#ifndef __SAMPLE_ANDROID_DEBUG_H__
#define __SAMPLE_ANDROID_DEBUG_H__
#include <android/log.h>
#include "utils.h"

#if 1
#ifndef MODULE_NAME
Expand Down
9 changes: 9 additions & 0 deletions app/src/main/cpp/utils.h
Original file line number Diff line number Diff line change
@@ -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

0 comments on commit 3280833

Please sign in to comment.