Создать видео файл на Android - PullRequest
0 голосов
/ 18 декабря 2018

В моем приложении для Android я пытаюсь создать видеофайл, добавляя звуковую дорожку в определенное время на видео.Я использовал MediaMuxer и изменил значение presentationTimeUs, чтобы сместить звук.Но, видимо, это не тот путь, потому что время начала видео также смещено.Другая проблема заключается в том, что mp3 аудио не работает.Вот моя попытка:

final long audioPositionUs = 10000000;
File fileOut = new File (Environment.getExternalStoragePublicDirectory (
  Environment.DIRECTORY_MOVIES) + "/output.mp4");
fileOut.createNewFile ();
MediaExtractor videoExtractor = new MediaExtractor ();
MediaExtractor audioExtractor = new MediaExtractor ();
AssetFileDescriptor videoDescriptor = getAssets ().openFd ("video.mp4");
// AssetFileDescriptor audioDescriptor = getAssets ().openFd ("audio.mp3"); // ?!
AssetFileDescriptor audioDescriptor = getAssets ().openFd ("audio.aac");
videoExtractor.setDataSource (videoDescriptor.getFileDescriptor (),
    videoDescriptor.getStartOffset (), videoDescriptor.getLength ());
audioExtractor.setDataSource (audioDescriptor.getFileDescriptor (),
    audioDescriptor.getStartOffset (), audioDescriptor.getLength ());
MediaFormat videoFormat = null;
for (int i = 0; i < videoExtractor.getTrackCount (); i++) {
  if (videoExtractor.getTrackFormat (i).getString (
      MediaFormat.KEY_MIME).startsWith ("video/")) {
    videoExtractor.selectTrack (i);
    videoFormat = videoExtractor.getTrackFormat (i);
    break;
  }
}
audioExtractor.selectTrack (0);
MediaFormat audioFormat = audioExtractor.getTrackFormat (0);
MediaMuxer muxer = new MediaMuxer (fileOut.getAbsolutePath (),
    MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);
int videoTrack = muxer.addTrack (videoFormat);
int audioTrack = muxer.addTrack (audioFormat);
boolean end = false;
int sampleSize = 256 * 1024;
ByteBuffer videoBuffer = ByteBuffer.allocate (sampleSize);
ByteBuffer audioBuffer = ByteBuffer.allocate (sampleSize);
MediaCodec.BufferInfo videoBufferInfo = new MediaCodec.BufferInfo ();
MediaCodec.BufferInfo audioBufferInfo = new MediaCodec.BufferInfo ();
videoExtractor.seekTo (0, MediaExtractor.SEEK_TO_CLOSEST_SYNC);
audioExtractor.seekTo (0, MediaExtractor.SEEK_TO_CLOSEST_SYNC);
muxer.start ();
while (!end) {
  videoBufferInfo.size = videoExtractor.readSampleData (videoBuffer, 0);
  if (videoBufferInfo.size < 0) {
    end = true;
    videoBufferInfo.size = 0;
  } else {
    videoBufferInfo.presentationTimeUs = videoExtractor.getSampleTime ();
    videoBufferInfo.flags = videoExtractor.getSampleFlags ();
    muxer.writeSampleData (videoTrack, videoBuffer, videoBufferInfo);
    videoExtractor.advance ();
  }
}
end = false;
while (!end) {
  audioBufferInfo.size = audioExtractor.readSampleData (audioBuffer, 0);
  if (audioBufferInfo.size < 0) {
    end = true;
    audioBufferInfo.size = 0;
  } else {
    audioBufferInfo.presentationTimeUs = audioExtractor.getSampleTime () +
        audioPositionUs;
    audioBufferInfo.flags = audioExtractor.getSampleFlags ();
    muxer.writeSampleData (audioTrack, audioBuffer, audioBufferInfo);
    audioExtractor.advance ();
  }
}
muxer.stop ();
muxer.release ();

Можете ли вы дать подробности (и, если возможно, код), чтобы помочь мне решить эту проблему?

Ответы [ 2 ]

0 голосов
/ 27 декабря 2018

Отправка образцов AudioRecord в оболочку MediaCodec + MediaMuxer.Использование системного времени в audioRecord.read (...) работает достаточно хорошо, как временная метка аудио, при условии, что вы будете проводить опрос достаточно часто, чтобы избежать заполнения внутреннего буфера AudioRecord (чтобы избежать смещения между временем, которое вы вызываете read, и временем, когда AudioRecord записал семплы).Жаль, что AudioRecord напрямую не передает метки времени ...

// Настройка AudioRecord

while (isRecording) {
    audioPresentationTimeNs = System.nanoTime();
    audioRecord.read(dataBuffer, 0, samplesPerFrame);
    hwEncoder.offerAudioEncoder(dataBuffer.clone(), audioPresentationTimeNs);
}

Обратите внимание, что AudioRecord гарантирует поддержку только 16-битных выборок PCM, хотя MediaCodec.queueInputBuffer принимает входные данные какбайт[].Передача байта [] в audioRecord.read (dataBuffer, ...) приведет к усечению разделения 16-битных выборок на 8-битные для вас.

Я обнаружил, что опрос таким способом все еще иногда генерирует timestampUs XXX

0 голосов
/ 27 декабря 2018

В качестве обходного пути вы можете создать временную звуковую дорожку, добавив звуковую дорожку в заголовок беззвучной дорожки, а затем использовать ее с addTrack.

PS: я бы подумал presentationTimeUsдолжно работать также.

PS2: возможно, setMediaCodec.BufferInfo метод *1007* может помочь.

...