Search code examples
androidnullpointerexceptionandroid-mediarecordermp4parser

Can't create a file or directory, Returns nullpointerexception


I have used mp4parser to append recorded audio. I am getting the following nullpointer exception errors when i click pause or stop button. I want the files to be stored in the external directory from cache. Cant understand where i made mistake.

07-22 13:21:18.847: I/RecordActivity(2478):
/data/data/com.example.audiorecordertest/cache/tmprecord
07-22 13:21:24.751: D/isoparser(2478): AbstractContainerBox:Parsing next() box
07-22 13:21:24.755: D/isoparser(2478): AbstractContainerBox:Parsing next() box
07-22 13:21:24.755: D/isoparser(2478): AbstractContainerBox:Parsing next() box
07-22 13:21:24.761: D/isoparser(2478): AbstractContainerBox:Parsing next() box
07-22 13:21:24.761: D/isoparser(2478): AbstractContainerBox:Parsing next() box
07-22 13:21:24.762: D/isoparser(2478): AbstractContainerBox:Parsing next() box
07-22 13:21:24.767: D/isoparser(2478): AbstractBox:mem mapping tkhd
07-22 13:21:24.767: D/isoparser(2478): AbstractBox:parsing details of tkhd
07-22 13:21:24.768: D/isoparser(2478): AbstractContainerBox:Parsing next() box
07-22 13:21:24.768: D/isoparser(2478): AbstractContainerBox:Parsing next() box
07-22 13:21:24.769: D/isoparser(2478): AbstractContainerBox:Parsing next() box
07-22 13:21:24.770: D/isoparser(2478): AbstractContainerBox:Parsing next() box
07-22 13:21:24.770: D/isoparser(2478): AbstractContainerBox:Parsing next() box
07-22 13:21:24.772: D/isoparser(2478): AbstractContainerBox:Parsing next() box
07-22 13:21:24.773: D/isoparser(2478): AbstractContainerBox:Parsing next() box
07-22 13:21:24.773: D/isoparser(2478): AbstractContainerBox:Parsing next() box
07-22 13:21:24.774: D/isoparser(2478): AbstractContainerBox:Parsing next() box
07-22 13:21:24.775: D/isoparser(2478): AbstractContainerBox:Parsing next() box
07-22 13:21:24.775: D/isoparser(2478): AbstractBox:mem mapping hdlr
07-22 13:21:24.775: D/isoparser(2478): AbstractBox:parsing details of hdlr
07-22 13:21:24.776: D/isoparser(2478): AbstractContainerBox:Parsing next() box
07-22 13:21:24.777: D/isoparser(2478): AbstractContainerBox:Parsing next() box
07-22 13:21:24.778: D/isoparser(2478): AbstractBox:mem mapping stts
07-22 13:21:24.778: D/isoparser(2478): AbstractBox:parsing details of stts
07-22 13:21:24.779: D/isoparser(2478): AbstractContainerBox:Parsing next() box
07-22 13:21:24.780: D/isoparser(2478): AbstractContainerBox:Parsing next() box
07-22 13:21:24.780: D/isoparser(2478): AbstractContainerBox:Parsing next() box
07-22 13:21:24.781: D/isoparser(2478): AbstractContainerBox:Parsing next() box
07-22 13:21:24.782: D/isoparser(2478): AbstractBox:mem mapping mdhd
07-22 13:21:24.782: D/isoparser(2478): AbstractBox:parsing details of mdhd
07-22 13:21:24.782: D/isoparser(2478): AbstractBox:mem mapping mvhd
07-22 13:21:24.782: D/isoparser(2478): AbstractBox:parsing details of mvhd
07-22 13:21:24.799: D/isoparser(2478): AbstractContainerBox:Parsing next() box
07-22 13:21:24.799: D/isoparser(2478): AbstractContainerBox:Parsing next() box
07-22 13:21:24.800: D/isoparser(2478): AbstractContainerBox:Parsing next() box
07-22 13:21:24.801: W/System.err(2478): java.lang.NullPointerException
07-22 13:21:24.803: W/System.err(2478): at com.googlecode.mp4parser.authoring.
container.mp4.MovieCreator.build(MovieCreator.java:48)
07-22 13:21:24.803: W/System.err(2478): at com.example.audiorecordertest.
Mp4ParserWrapper.append(Mp4ParserWrapper.java:72)
07-22 13:21:24.803: W/System.err(2478): at com.example.audiorecordertest.
Mp4ParserWrapper.append(Mp4ParserWrapper.java:34)
07-22 13:21:24.803: W/System.err(2478): at com.example.audiorecordertest.
RecordActivity.appendToFile(RecordActivity.java:179)
07-22 13:21:24.803: W/System.err(2478): at com.example.audiorecordertest.
RecordActivity.access$7(RecordActivity.java:178)
07-22 13:21:24.803: W/System.err(2478): at com.example.audiorecordertest.
RecordActivity$2.onClick(RecordActivity.java:108)
07-22 13:21:24.804: W/System.err(2478): at
android.view.View.performClick(View.java:4456)
07-22 13:21:24.804: W/System.err(2478):     at
android.view.View$PerformClick.run(View.java:18465)
07-22 13:21:24.805: W/System.err(2478): at
android.os.Handler.handleCallback(Handler.java:733)
07-22 13:21:24.805: W/System.err(2478): at
android.os.Handler.dispatchMessage(Handler.java:95)
07-22 13:21:24.805: W/System.err(2478): at android.os.Looper.loop(Looper.java:136)
07-22 13:21:24.805: W/System.err(2478): at
android.app.ActivityThread.main(ActivityThread.java:5086)
07-22 13:21:24.806: W/System.err(2478): at 
java.lang.reflect.Method.invokeNative(Native Method)
07-22 13:21:24.806: W/System.err(2478): at
java.lang.reflect.Method.invoke(Method.java:515)
07-22 13:21:24.807: W/System.err(2478): at
com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:785)
07-22 13:21:24.807: W/System.err(2478): at
com.android.internal.os.ZygoteInit.main(ZygoteInit.java:601)
07-22 13:21:24.808: W/System.err(2478): at
dalvik.system.NativeStart.main(Native Method)

This is my code:

RecordActivity

import java.io.File;
import java.io.IOException;

import android.support.v7.app.ActionBarActivity;
import android.annotation.SuppressLint;
import android.content.Context;
import android.media.MediaRecorder;
import android.os.Bundle;
import android.os.Environment;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.ImageButton;

public class RecordActivity extends ActionBarActivity {

protected static final String TAG = "RecordActivity";
private ImageButton start_btn,pause_btn,stop_btn;
private MediaRecorder myrecorder = null;
Context mcontext;
private String outputFile;
private String mTargetRecordFileName;


@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_record);
    mcontext = this;
    start_btn = (ImageButton) findViewById(R.id.im_start_btn);
    pause_btn = (ImageButton) findViewById(R.id.im_pause_btn);
    stop_btn = (ImageButton) findViewById(R.id.im_stop_btn);
    stop_btn.setVisibility(View.INVISIBLE);
    pause_btn.setVisibility(View.INVISIBLE);
    start_btn.setEnabled(true);

    mTargetRecordFileName = getOutputFile();

    start_btn.setOnClickListener(new OnClickListener() {

        @SuppressLint("InlinedApi")
        @Override
        public void onClick(View v) {
            // TODO Auto-generated method stub
            start_btn.setVisibility(View.INVISIBLE);
            pause_btn.setVisibility(View.VISIBLE);
            stop_btn.setVisibility(View.VISIBLE);
            start_btn.setEnabled(false);
            pause_btn.setEnabled(true);
            myrecorder = new MediaRecorder();

            myrecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
            myrecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
            myrecorder.setAudioEncoder(MediaRecorder.OutputFormat.AMR_NB);
            myrecorder.setOutputFile(getTemporaryFileName());
            start(v);

        }

        private void start(View v) {
            // TODO Auto-generated method stub
            try{
            myrecorder.prepare();
            myrecorder.start();
            Log.i(TAG, getTemporaryFileName());
        } catch(IllegalStateException e){

        } catch(IOException e){

        }
        }
    });

    pause_btn.setOnClickListener(new OnClickListener() {

        @Override
        public void onClick(View v) {
            // TODO Auto-generated method stub

            appendToFile(mTargetRecordFileName, getTemporaryFileName());
            myrecorder.stop();
            myrecorder.reset();
            myrecorder.release();
            pause_btn.setVisibility(View.INVISIBLE);
            start_btn.setVisibility(View.VISIBLE);
            stop_btn.setVisibility(View.VISIBLE);
            start_btn.setEnabled(true);
            stop_btn.setEnabled(true);

        }
    });

    stop_btn.setOnClickListener(new OnClickListener() {

        @Override
        public void onClick(View v) {
            // TODO Auto-generated method stub

              myrecorder.stop();     // stop recording
              myrecorder.reset();    // set state to idle
              myrecorder.release();  // release resources back to the system
              myrecorder = null;
              appendToFile(mTargetRecordFileName, getTemporaryFileName());
              start_btn.setVisibility(View.VISIBLE);
              pause_btn.setVisibility(View.INVISIBLE);
              start_btn.setEnabled(true);
        }
    });
}

private String getOutputFile()
{
    String path = Environment.getExternalStorageDirectory().
getAbsolutePath() +  "/MyFolder/";
    File dir = new File(path);
    if(!dir.exists())
        dir.mkdirs();
    outputFile = path + File.separator + "MA_"+"Srijith".subSequence(0, 3);
    return outputFile;
}

private String getTemporaryFileName() {

    return mcontext.getCacheDir().getAbsolutePath() + File.separator + "tmprecord";
}

private void appendToFile(final String targetFileName,final String newFileName) {
    Mp4ParserWrapper.append(targetFileName, newFileName);
}

@Override
   protected void onDestroy() {
      super.onDestroy();
      try {
         trimCache(getApplicationContext());
      } catch (Exception e) {
         // TODO Auto-generated catch block
         e.printStackTrace();
      }
   }

   public static void trimCache(Context context) {
      try {
         File dire = context.getCacheDir();
         if (dire != null && dire.isDirectory()) {
            //deleteDir(dire);
             deleteDir(dire);
         }
      } catch (Exception e) {
         // TODO: handle exception
      }
   }

private static boolean deleteDir(File dire) {
    // TODO Auto-generated method stub
    if (dire != null && dire.isDirectory()) {
         String[] children = dire.list();
         for (int i = 0; i < children.length; i++) {
            boolean success = deleteDir(new File(dire, children[i]));
            if (!success) {
               return false;
            }
         }
      }

      return dire.delete();
}
}

Mp4ParserWrapper

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.channels.Channels;
import java.nio.channels.WritableByteChannel;
import java.util.List;

import android.util.Log;

import com.coremedia.iso.boxes.Container;
import com.googlecode.mp4parser.FileDataSourceImpl;
import com.googlecode.mp4parser.authoring.Movie;
import com.googlecode.mp4parser.authoring.Track;
import com.googlecode.mp4parser.authoring.builder.DefaultMp4Builder;
import com.googlecode.mp4parser.authoring.container.mp4.MovieCreator;
import com.googlecode.mp4parser.authoring.tracks.AppendTrack;

public class Mp4ParserWrapper {
public static final int FILE_BUFFER_SIZE = 1024;
private static final String TAG = "Mp4ParserWrapper";


public static boolean append(String mainFileName, String anotherFileName){
    boolean rvalue = false;
    try{
        File targetFile = new File(mainFileName);
        File anotherFile = new File(anotherFileName);
        if (targetFile.exists() && targetFile.length() > 0) {
            String tmpFileName = mainFileName + ".tmp";
            append(mainFileName, anotherFileName, tmpFileName);
            copyFile(tmpFileName, mainFileName);
            rvalue = anotherFile.delete() && new File(tmpFileName).delete();
        } else if (targetFile.createNewFile()) {
            copyFile(anotherFileName, mainFileName);
            rvalue = anotherFile.delete();
    }
    } catch (IOException e) {
        Log.e(TAG,"Append two mp4 files exception", e);
    } catch(NullPointerException ex){
        ex.printStackTrace();
    }
    return rvalue;

}

public static void copyFile(final String from, final String destination)
        throws IOException {
    FileInputStream in = new FileInputStream(from);
    FileOutputStream out = new FileOutputStream(destination);
    copy(in, out);
    in.close();
    out.close();
}

public static void copy(FileInputStream in, FileOutputStream out) throws IOException {
    byte[] buf = new byte[FILE_BUFFER_SIZE];
    int len;
    while ((len = in.read(buf)) != -1) {
        out.write(buf, 0, len);
    }
}

public static void append(
        final String firstFile,
        final String secondFile,
        final String newFile) throws IOException {
    final Movie movieA = MovieCreator.build(new FileDataSourceImpl(secondFile));
    final Movie movieB = MovieCreator.build(new FileDataSourceImpl(firstFile));

    final Movie finalMovie = new Movie();

    final List<Track> movieOneTracks = movieA.getTracks();
    final List<Track> movieTwoTracks = movieB.getTracks();

    for (int i = 0; i < movieOneTracks.size() || i < movieTwoTracks.size(); ++i) {
        finalMovie.addTrack(new 
        AppendTrack(movieTwoTracks.get(i), movieOneTracks.get(i)));
    }

    final Container container = new DefaultMp4Builder().build(finalMovie);

    final FileOutputStream fos = new FileOutputStream(new File(String.format(newFile)));
    final WritableByteChannel bb = Channels.newChannel(fos);
    container.writeContainer(bb);
    fos.close();

}

}

Please help.


Solution

  • Check these two lines:

    final Movie movieA = MovieCreator.build(new FileDataSourceImpl(secondFile));
    final Movie movieB = MovieCreator.build(new FileDataSourceImpl(firstFile));
    

    There are no line numbers so I can't see which one of them is line 72 in the Mp4ParserWrapper class, but that's where the error appears. If I understand it right, the variable secondFile was initialized via getTemporaryFileName(), which looks very suspicious. Shouldn't it rather point to some movie file?

    --- edit based on your comment:

    I never worked with MovieCreator and can't find much about it, but I guess you're using the append function in the wrong way.

    public static void append(
        final String firstFile,
        final String secondFile,
        final String newFile)
    

    You initilize your the firstFile and the secondFile as outputs. But if I understand it right, these should actually be input files. So you should point firstFile to one mp4 file and secondFile to another mp4 file. And the append function joins the tracks of these two files into one file. In newFile you should specify the path where you want this resulting new file to be saved.