I want to make a dubbing app in Android.
Flow of the app is:
Get video and audio from the gallery.
Reduce the original sound of Video file. And mix (Dub) the selected audio on this video file.
After mixing the audio on this video file save it in to external memory.
I am using MediaMuxer for this, but m not success. Please help me regarding this.
Regards,
Prateek
even i was looking for the same to dub my video with an audio using mediaMuxer, MediaMuxer was a little difficult concept for me to understand as i am beginner . i ended up refering this github code. https://github.com/tqnst/MP4ParserMergeAudioVideo
it was my saviour. really thanx to that person.
i just picked up the code i wanted from it, i.e dubbing a video with the audio i specify.
here is my code i used in my project below
private void mergeAudioVideo(String originalVideoPath,String AudioPath,String OutPutVideoPath) {
// TODO Auto-generated method stub
Movie video = null;
try {
new MovieCreator();
video = MovieCreator.build(originalVideoPath);
} catch (RuntimeException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
Movie audio = null;
try {
new MovieCreator();
audio = MovieCreator.build(AudioPath);
} catch (IOException e) {
e.printStackTrace();
} catch (NullPointerException e) {
e.printStackTrace();
}
List<Track> videoTracks = new LinkedList<Track>();
for (Track t : video.getTracks()) {
if (t.getHandler().equals("vide")) {
videoTracks.add(t);
//seperate the video from the orginal video
}
}
Track audioTrack = audio.getTracks().get(0);// get your audio track to dub the video
Movie result = new Movie();
result.addTrack(videoTracks.get(0)); // add the video seprated from the originals
result.addTrack(audioTrack); //add the track to be put in resul video
Container out = new DefaultMp4Builder().build(result);
FileOutputStream fos = null;
try {
fos = new FileOutputStream(OutPutVideoPath);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
BufferedWritableFileByteChannel byteBufferByteChannel = new BufferedWritableFileByteChannel(fos);
try {
out.writeContainer(byteBufferByteChannel);
byteBufferByteChannel.close();
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
and here is the BufferedWritableFileByteChannel class to write the outputVideo data to the directory.
public class BufferedWritableFileByteChannel implements WritableByteChannel {
private static final int BUFFER_CAPACITY = 1000000;
private boolean isOpen = true;
private final OutputStream outputStream;
private final ByteBuffer byteBuffer;
private final byte[] rawBuffer = new byte[BUFFER_CAPACITY];
public BufferedWritableFileByteChannel(OutputStream outputStream) {
this.outputStream = outputStream;
this.byteBuffer = ByteBuffer.wrap(rawBuffer);
}
#Override
public int write(ByteBuffer inputBuffer) throws IOException {
int inputBytes = inputBuffer.remaining();
if (inputBytes > byteBuffer.remaining()) {
dumpToFile();
byteBuffer.clear();
if (inputBytes > byteBuffer.remaining()) {
throw new BufferOverflowException();
}
}
byteBuffer.put(inputBuffer);
return inputBytes;
}
#Override
public boolean isOpen() {
return isOpen;
}
#Override
public void close() throws IOException {
dumpToFile();
isOpen = false;
}
private void dumpToFile() {
try {
outputStream.write(rawBuffer, 0, byteBuffer.position());
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
and dont forget to add the libraries in your project.
this may not be the exact answer to your question. but atleast it will able to shed some light on the probable solution.
Related
I am trying to write Short[] to wav audio file using file output stream but the file only contains scratch sound.
The reason i am using short[] rather than byte[] is because i am trying to use an external library which provides Voice Activity Detection . I did add wav header provided in Android Audio Record to wav and i tried to convert Short[] to byte[] using Converting Short array from Audio Record to Byte array without degrading audio quality? but none of the above links were able to help me.
Here is my code:
private class ProcessVoice implements Runnable {
#Override
public void run() {
File fl = new File(filePath, AUDIO_RECORDING_FILE_NAME);
try {
os = new BufferedOutputStream(new FileOutputStream(fl));
} catch (FileNotFoundException e) {
Log.w(TAG, "File not found for recording ");
}
android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_AUDIO);
while (!Thread.interrupted() && isListening && audioRecord != null) {
short[] buffer = new short[vad.getConfig().getFrameSize().getValue() * getNumberOfChannels() * 2];
audioRecord.read(buffer, 0, buffer.length);
isSpeechDetected(buffer);
}
}
private void isSpeechDetected(final short[] buffer) {
vad.isContinuousSpeech(buffer, new VadListener() {
#Override
public void onSpeechDetected() {
callback.onSpeechDetected();
bytes2 = new byte[buffer.length * 2];
ByteBuffer.wrap(bytes2).order(ByteOrder.LITTLE_ENDIAN).asShortBuffer().put(buffer);
//Log.w(TAG, String.valueOf(buffer));
try {
// // writes the data to file from buffer
// // stores the voice buffer
os.write(header, 0, 44);
working = true;
os.write(bytes2, 0, bytes2.length);
} catch (IOException e) {
e.printStackTrace();
}
}
#Override
public void onNoiseDetected() {
callback.onNoiseDetected();
if(working == true){
working = false;
try {
doneRec();
} catch (IOException e) {
e.printStackTrace();
}
}
//Log.w(TAG, String.valueOf(bytes2));
}
});
}
}
I have been trying to do it in different ways, but all the "lists" want int or string and I have Assetfiledescriptor stuff to work with.
How can I create a list of certain mp3 files, which are located in the activity expansionfile, that I can use for oncompletionlisteners, etc?
They all work fine individually, but I want to play them after each other.
Here are a few files that I would use:
AssetFileDescriptor dfFn01, dfFn02, dfFn03 = null;
dfFn01 = expansionFile.getAssetFileDescriptor("l1r_df_l6.mp3");
dfFn02 = expansionFile.getAssetFileDescriptor("l1r_df_l7.mp3");
dfFn03 = expansionFile.getAssetFileDescriptor("df_jp_l1r03.mp3");
Here is the player that starts from a buttonclick:
public void setWholeEngAudio(AssetFileDescriptor fd) throws IllegalStateException {
try {
stopPlayers();
wholeTextPlayer = new MediaPlayer();
wholeTextPlayer.reset();
wholeTextPlayer.setDataSource(fd.getFileDescriptor(), fd.getStartOffset(), fd.getLength());
try {
wholeTextPlayer.prepare();
} catch (IllegalArgumentException e) {
e.printStackTrace();
}
wholeTextPlayer.start();
seekBar.setProgress(0);
seekBar.setMax(100);
updateSeekBar();
setThumbState();
} catch (Exception e) {
e.printStackTrace();
}
}
Thanks
I implemented a file chooser on a media player which returns the file paths for an .mp3 and an .srt on the externalSD. The audio plays fine. But when I call addTimedTextSource with the path to the .srt, it throws a null pointer exception. So, I put in an If(file.exists). It also returns a null. I tried moving the file to the internal SD with the same result. Any ideas?
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_player);
txtDisplay = (TextView) findViewById(R.id.txtDisplay);
buttonPause = (Button) findViewById(R.id.buttonPause);
buttonPlay = (Button) findViewById(R.id.buttonPlay);
Bundle bundle = getIntent().getExtras();
if(bundle!=null) {
String removeString = "file:";
soundPath = bundle.getString("soundFile");
subPath = bundle.getString("subFile");
subPath = removeString(subPath,removeString);
soundFile = new File(soundPath);
subFile = new File(subPath);
}
player = new MediaPlayer();
try {
player.setDataSource(soundPath);
player.setOnErrorListener(this);
player.setOnPreparedListener(this);
player.prepareAsync();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
} catch (IllegalStateException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
public void onPrepared(MediaPlayer mp){
mp.setOnTimedTextListener(this);
if(subFile.exists() {
try {
player.addTimedTextSource(subFile.getAbsolutePath(), MediaPlayer.MEDIA_MIMETYPE_TEXT_SUBRIP);
} catch (IOException e) {
Log.v("Hey Here is a Problem: ", e.getMessage());
}
TrackInfo[] ti = player.getTrackInfo();
for (int i = 0; i < ti.length; i++) {
if (ti[i].getTrackType() == TrackInfo.MEDIA_TRACK_TYPE_TIMEDTEXT) {
player.selectTrack(i);
break;
}
}
}else{
onBackPressed();
}
mp.start();
}
Edit:
Rereading your question, it appears that subfile.exists() returns true, but you get a null pointer exception when you try to call player.addTimedTextSource().
Assuming player is not null, I'd like you to try this:
string fileStr = subfile.getAbsolutePath();
player.addTimedTextSource(fileStr, MediaPlayer.MEDIA_MIMETYPE_TEXT_SUBRIP);
I suspect that you may be running into an issue with the overloads of addTimedTextSource().
Old answer:
So, I put in an If(file.exists). It also returns a null. I tried
moving the file to the internal SD with the same result. Any ideas?
There is no file at the provided path. Since you have moved the file, seems like you're mistyping the file name.
I want to write audio data that comes from the microphone to a file.
I have 2 threads: one "listen" for the audio data and send it to the second thread(the consumer) which stores it in a queue. The consumer thread constantly polls the queue and writes on the file the audioData as byte[].
I use RandomAccessFile for the writing. Considering that everything is syncronized in my code, should I use some non-thread-safe class like FileChannel?
below is some code snippets:
Read audio data
private void read(){
// fill the buffer with the mic input
readFully(buffer, 0, buffer.length);
// creates audioData from this buffer
WAVData audioData = new WAVData(buffer.length);
audioData.arrayCopy(buffer);
// add it to the consumer
mAudioWritter.add(audioData);
}
Write audio data - the consumer clas
public void add(WAVEntity audioEntity){
mQueue.add(audioEntity);
synchronized (mLock) {
mLock.notify();
}
}
#Override
public void run() {
synchronized (mLock) {
while(!isFinalized){
//wait if queue is empty
while(mQueue.isEmpty()){
try {
mLock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
WAVEntity entity = mQueue.poll();
if(entity != null){
try {
entity.writeOnFile(file);
} catch (AudioRecorderError e) {
// error handling
}
}
}
}
callback.threadFinished(this);
// try closing this file
try {
file.close();
} catch (IOException e) {
Log.e(getClass().getName(), e.getMessage(), e);
}
}
#Override
public boolean writeOnFile(RandomAccessFile fWriter) throws AudioRecorderError {
synchronized (data) {
//write on the file
try {
fWriter.write(data);
} catch (Exception e) {
AudioRecorderError error = new AudioRecorderError(e, "Data chunck was not written. See stack trace.");
throw error;
}
}
return false;
}
So, I'm developing a custom video player for Android but I need to play more than the android supported video files (mp4, 3gp...), like wmv, avi, flv.
At this time I do already convert any video type to .mp4 and I'm able to play them after recoding, but I have no idea how can I play those wmv, avi files without recoding them to mp4 video formats.
Is there any way I can play any video on Android without recoding them?
JavaCV + FFmpeg library already working, just don't know how to do that.
By the way, heres the code that I'm using to recode videos:
public static void convert(File file) {
FFmpegFrameGrabber frameGrabber =
new FFmpegFrameGrabber(file.getAbsolutePath());
IplImage captured_frame = null;
FrameRecorder recorder = null;
recorder = new FFmpegFrameRecorder("/mnt/sdcard/external_sd/videosteste/primeiroteste.mp4", 300, 300);
recorder.setVideoCodec(13);
recorder.setFrameRate(30);
recorder.setFormat("mp4");
try {
recorder.start();
frameGrabber.start();
while (true) {
try {
captured_frame = frameGrabber.grab();
if (captured_frame == null) {
System.out.println("!!! Failed cvQueryFrame");
break;
}
recorder.record(captured_frame);
} catch (Exception e) {
}
}
recorder.stop();
recorder.release();
} catch (Exception e) {
e.printStackTrace();
}
}
first you create the CanvasFrame then use "canvas.showImage(captured_frame);" instead of "recorder.record(captured_frame);"
Here is the code:
public class GrabberShow implements Runnable
{
final static int INTERVAL=40;///you may use interval
IplImage image;
static CanvasFrame canvas = new CanvasFrame("JavaCV player");
public GrabberShow()
{
canvas.setDefaultCloseOperation(javax.swing.JFrame.EXIT_ON_CLOSE);
}
public static void convert(File file)
{
FFmpegFrameGrabber frameGrabber = new FFmpegFrameGrabber(file.getAbsolutePath());
IplImage captured_frame = null;
FrameRecorder recorder = null;
//recorder = new FFmpegFrameRecorder("/mnt/sdcard/external_sd/videosteste/primeiroteste.mp4", 300, 300);
recorder = new FFmpegFrameRecorder("D://temp.mp4", 300, 300);
recorder.setVideoCodec(13);
recorder.setFrameRate(30);
recorder.setFormat("mp4");
try {
recorder.start();
frameGrabber.start();
while (true) {
try {
captured_frame = frameGrabber.grab();
if (captured_frame == null) {
System.out.println("!!! Failed cvQueryFrame");
break;
}
//recorder.record(captured_frame);
canvas.showImage(captured_frame);
Thread.sleep(INTERVAL);
} catch (Exception e) {
}
}
recorder.stop();
recorder.release();
} catch (Exception e) {
e.printStackTrace();
}
}
#Override
public void run()
{
convert(new File("D://aes.mp4"));
}
public static void main(String[] args) {
GrabberShow gs = new GrabberShow();
Thread th = new Thread(gs);
th.start();
}
}
Is there any way I can play any video on Android without recoding them?
Why are you recording the Video?? There is no need to record the video. JavaCv.
This is sample code for giving you the idea, how you can achieve it.
FrameGrabber grabber = new FrameGrabber(videoFile);
grabber.start();
BufferedImage image= null;
while((image=grabber.grab())!=null){
// TODO set the image on the canvas or panel where ever you want.
}
grabber.stop();