it-swarm-vi.tech

Tạo một tệp video trên Android

Trong ứng dụng Android của tôi, tôi đang cố gắng tạo tệp video, thêm đoạn âm thanh ở vị trí thời gian nhất định trên video . Tôi đã sử dụng MediaMuxer và thay đổi giá trị presentationTimeUs để thay đổi âm thanh . rõ ràng đây không phải là hướng đi, vì thời gian bắt đầu của video cũng bị thay đổi . Một vấn đề khác là âm thanh mp3 không hoạt động . Đây là nỗ lực của tôi cho đến nay:

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 ();

Bạn có thể vui lòng cho biết chi tiết (và mã nếu có thể) để giúp tôi giải quyết vấn đề này không?

7
Patrick

Gửi mẫu của AudioRecord đến trình bao bọc MediaCodec + MediaMuxer. Sử dụng thời gian hệ thống tại audioRecord.read (...) hoạt động đủ tốt như dấu thời gian âm thanh, với điều kiện bạn thường xuyên thăm dò ý kiến ​​để tránh lấp đầy bộ đệm bên trong của AudioRecord (để tránh trôi giữa thời gian bạn gọi đọc và thời gian AudioRecord ghi lại các mẫu ). Quá tệ AudioRecord không giao tiếp trực tiếp dấu thời gian ...

// Cài đặt AudioRecord

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

Lưu ý rằng AudioRecord chỉ đảm bảo hỗ trợ cho các mẫu PCM 16 bit, mặc dù MediaCodec.queueInputBuffer lấy đầu vào là byte []. Truyền một byte [] cho audioRecord.read (dataBuffer, ...) sẽ cắt ngắn các mẫu 16 bit thành 8 bit cho bạn.

Tôi thấy rằng việc bỏ phiếu theo cách này đôi khi vẫn tạo ra dấu thời gian. XXX <lastTimestampUs XXX cho lỗi theo dõi âm thanh, vì vậy tôi đã đưa vào một số logic để theo dõi bộ đệm mediaMuxer.writeSampleData (track Index ,odingData, bufferInfo).

1
umer farooq

Như một giải pháp thay thế, bạn có thể tạo một bản nhạc âm thanh tạm thời bằng cách đệm đoạn âm thanh của bạn ở đầu bằng một bản nhạc im lặng, sau đó sử dụng nó với addTrack.

PS: Tôi đã nghĩ presentationTimeUs cũng nên hoạt động.

PS2: có lẽ phương thức set của MediaCodec.BufferInfo có thể giúp ích.

0
sancho.s