m4a encoding

This commit is contained in:
Alexey Kuznetsov 2016-03-11 20:42:34 +03:00
commit d422f68e41
7 changed files with 150 additions and 16 deletions

View file

@ -37,16 +37,16 @@ import android.widget.Toast;
import com.github.axet.audiorecorder.R;
import com.github.axet.audiorecorder.app.MainApplication;
import com.github.axet.audiorecorder.app.Storage;
import com.github.axet.audiorecorder.encoders.FileEncoder;
import com.github.axet.audiorecorder.encoders.Encoder;
import com.github.axet.audiorecorder.encoders.EncoderInfo;
import com.github.axet.audiorecorder.encoders.Wav;
import com.github.axet.audiorecorder.encoders.FileEncoder;
import com.github.axet.audiorecorder.encoders.FormatM4A;
import com.github.axet.audiorecorder.encoders.FormatWAV;
import com.github.axet.audiorecorder.widgets.PitchView;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.concurrent.atomic.AtomicLong;
public class RecordingActivity extends AppCompatActivity {
public static final String TAG = RecordingActivity.class.getSimpleName();
@ -551,7 +551,19 @@ public class RecordingActivity extends AppCompatActivity {
EncoderInfo info = getInfo();
encoder = new FileEncoder(this, in, new Wav(info, out));
Encoder e = null;
SharedPreferences shared = PreferenceManager.getDefaultSharedPreferences(this);
String ext = shared.getString(MainApplication.PREFERENCE_ENCODING, "");
if (ext.equals("wav")) {
e = new FormatWAV(info, out);
}
if (ext.equals("m4a")) {
e = new FormatM4A(info, out);
}
encoder = new FileEncoder(this, in, e);
final ProgressDialog d = new ProgressDialog(this);
d.setTitle("Encoding...");
@ -564,8 +576,7 @@ public class RecordingActivity extends AppCompatActivity {
encoder.run(new Runnable() {
@Override
public void run() {
int i = encoder.getProgress();
d.setProgress(i);
d.setProgress(encoder.getProgress());
}
}, new Runnable() {
@Override

View file

@ -217,7 +217,15 @@ public class SettingsActivity extends AppCompatPreferenceActivity {
bindPreferenceSummaryToValue(findPreference(MainApplication.PREFERENCE_STORAGE));
}
bindPreferenceSummaryToValue(findPreference(MainApplication.PREFERENCE_RATE));
Preference rate = findPreference(MainApplication.PREFERENCE_RATE);
if (Build.VERSION.SDK_INT < 21) {
getPreferenceScreen().removePreference(rate);
} else {
bindPreferenceSummaryToValue(rate);
}
bindPreferenceSummaryToValue(findPreference(MainApplication.PREFERENCE_ENCODING));
}
@Override

View file

@ -52,10 +52,10 @@ public class FileEncoder {
int len = is.read(buf);
if (len <= 0) {
Log.d("23", "end");
handler.post(done);
return;
}
if (len > 0) {
} else {
short[] shorts = new short[len / 2];
ByteBuffer.wrap(buf, 0, len).order(ByteOrder.BIG_ENDIAN).asShortBuffer().get(shorts);
encoder.encode(shorts);
@ -65,10 +65,13 @@ public class FileEncoder {
}
}
}
Log.d("23", "interrupted " + Thread.currentThread().isInterrupted());
} catch (IOException e) {
Log.d("23", "error " + e.getMessage());
t = e;
handler.post(error);
} finally {
Log.d("23", "close");
encoder.close();
if (is != null) {
try {

View file

@ -0,0 +1,112 @@
package com.github.axet.audiorecorder.encoders;
import android.annotation.TargetApi;
import android.media.MediaCodec;
import android.media.MediaCodecInfo;
import android.media.MediaFormat;
import android.media.MediaMuxer;
import java.io.File;
import java.io.IOException;
import java.nio.ByteBuffer;
@TargetApi(21)
public class FormatM4A implements Encoder {
EncoderInfo info;
MediaCodec encoder;
MediaMuxer muxer;
int audioTrackIndex;
long NumSamples;
public FormatM4A() {
}
public FormatM4A(EncoderInfo info, File out) {
this.info = info;
MediaFormat format = new MediaFormat();
format.setString(MediaFormat.KEY_MIME, "audio/mp4a-latm");
format.setInteger(MediaFormat.KEY_AAC_PROFILE, MediaCodecInfo.CodecProfileLevel.AACObjectHE);
format.setInteger(MediaFormat.KEY_SAMPLE_RATE, info.sampleRate);
format.setInteger(MediaFormat.KEY_CHANNEL_COUNT, info.channels);
format.setInteger(MediaFormat.KEY_BIT_RATE, 128 * 1024);
try {
encoder = MediaCodec.createEncoderByType("audio/mp4a-latm");
encoder.configure(format, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
encoder.start();
muxer = new MediaMuxer(out.getAbsolutePath(), MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
public void encode(short[] buf) {
int len = buf.length * 2;
int inputIndex = encoder.dequeueInputBuffer(-1);
if (inputIndex >= 0) {
ByteBuffer input = encoder.getInputBuffer(inputIndex);
input.clear();
for (int i = 0; i < buf.length; i++)
input.putShort(buf[i]);
encoder.queueInputBuffer(inputIndex, 0, len, getCurrentTimeStamp(), 0);
}
NumSamples += buf.length / info.channels;
encode();
}
void encode() {
MediaCodec.BufferInfo outputInfo = new MediaCodec.BufferInfo();
int outputIndex = encoder.dequeueOutputBuffer(outputInfo, 0);
if (outputIndex == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
audioTrackIndex = muxer.addTrack(encoder.getOutputFormat());
muxer.start();
}
while (outputIndex >= 0) {
ByteBuffer output = encoder.getOutputBuffer(outputIndex);
output.position(outputInfo.offset);
output.limit(outputInfo.offset + outputInfo.size);
// byte[] out = new byte[outputInfo.size];
// output.get(out);
muxer.writeSampleData(audioTrackIndex, output, outputInfo);
encoder.releaseOutputBuffer(outputIndex, false);
outputIndex = encoder.dequeueOutputBuffer(outputInfo, 0);
}
}
public void close() {
end();
encode();
encoder.stop();
encoder.release();
muxer.stop();
muxer.release();
}
long getCurrentTimeStamp() {
return NumSamples * 1000 * 1000 / info.sampleRate;
}
void end() {
int inputIndex = encoder.dequeueInputBuffer(-1);
if (inputIndex >= 0) {
ByteBuffer input = encoder.getInputBuffer(inputIndex);
input.clear();
encoder.queueInputBuffer(inputIndex, 0, 0, getCurrentTimeStamp(), MediaCodec.BUFFER_FLAG_END_OF_STREAM);
}
}
public EncoderInfo getInfo() {
return info;
}
}

View file

@ -8,7 +8,7 @@ import java.io.*;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
public class Wav implements Encoder {
public class FormatWAV implements Encoder {
int NumSamples;
EncoderInfo info;
int BytesPerSample;
@ -16,10 +16,10 @@ public class Wav implements Encoder {
ByteOrder order = ByteOrder.LITTLE_ENDIAN;
public Wav() {
public FormatWAV() {
}
public Wav(EncoderInfo info, File out) {
public FormatWAV(EncoderInfo info, File out) {
this.info = info;
NumSamples = 0;

View file

@ -23,12 +23,12 @@
<string-array name="encodings" >
<item>.wav (default)</item>
<item>.aac</item>
<item>.m4a</item>
</string-array>
<string-array name="encodings_values" >
<item>wav</item>
<item>aac</item>
<item>m4a</item>
</string-array>
<string name="title_activity_main">Audio Recorder</string>

View file

@ -22,7 +22,7 @@
android:key="encoding"
android:negativeButtonText="@null"
android:positiveButtonText="@null"
android:summary="Output file formats (.wav, .aac, ...)"
android:summary="Output file formats (.wav, .m4a, ...)"
android:title="Encoding" />
<SwitchPreference