Major problems solved
1. Separate MP4 into RAW data, AAC and H264
2. Separate MP4 into audio and video
3. Repackage audio and video as MP4
MediaExtractor: Audio and video data separator for demultiplexing (Demuxer)
Get the demultiplexed information
// Check the video information
// Demultiplexer demuxer
val mediaExtractor = MediaExtractor();
mediaExtractor.setDataSource(videoPath);
val numTracks = mediaExtractor.trackCount;
println("extrarot streams $numTracks;")
for (i in 0 until numTracks) {
val mediaFormat = mediaExtractor.getTrackFormat(i)
val mine = mediaFormat.getString(MediaFormat.KEY_MIME)
println("stream $i mime: $mine")}// Prints information
2021-04-16 18:30:21.099 /System.out: extrarot streams 2;
2021-04-16 18:30:21.099 /System.out: stream 0 mime: video/avc
2021-04-16 18:30:21.100 /System.out: stream 1 mime: audio/mp4a-latm
Copy the code
Get Audio and Video
var audioFrameIndex = -1
var videoFrameIndex = -1
for (i in 0 until numTracks) {
val mediaFormat = mediaExtractor.getTrackFormat(i)
val mine = mediaFormat.getString(MediaFormat.KEY_MIME)// Get the MIME format content
println("stream $i [mime: $mine]. "")
if(mine? .startsWith("video/")!! { videoFrameIndex = i }if (mine.startsWith("audio/")) {
audioFrameIndex = i
}
}
Copy the code
Example 1: Parse and save audio information, < raw data > saved data cannot be processed.
if(audioFrameIndex ! = -1) { mediaExtractor.selectTrack(audioFrameIndex) val outAudioFile = File("$filesDir/a1.aac") outAudioFile.deleteOnExit() val fos = FileOutputStream(outAudioFile) val byteBuffer = ByteBuffer.allocate(1024 * 1024) val byteArray = ByteArray(byteBuffer.capacity()); while (true) { val readCount = mediaExtractor.readSampleData(byteBuffer, 0) if (readCount < 0) { println(Reading no audio data, stop!) break } println("Write audio data [$readCount] bytes") byteBuffer.get(byteArray, 0, readCount) fos.write(byteArray, 0, readCount) byteBuffer.clear() mediaExtractor.advance() if(! mediaExtractor.advance()) { println("No data after switch to next read point, stop!") break } } fos.flush() fos.close() mediaExtractor.unselectTrack(audioFrameIndex) } Copy the code
Example 2: Parse and save video information, < raw data > saved data cannot be processed.
if(videoFrameIndex ! = -1) { mediaExtractor.selectTrack(videoFrameIndex) val outVideoFile = File("$filesDir/a1.h264") outVideoFile.deleteOnExit() val fos = FileOutputStream(outVideoFile) val byteBuffer = ByteBuffer.allocate(1024 * 1024) val byteArray = ByteArray(byteBuffer.capacity()); while (true) { val readCount = mediaExtractor.readSampleData(byteBuffer, 0) if (readCount < 0) { println("Reading no video data, stop!") break } println("Write video data [$readCount] bytes") byteBuffer.get(byteArray, 0, readCount) fos.write(byteArray, 0, readCount) byteBuffer.clear() mediaExtractor.advance() if(! mediaExtractor.advance()) { println("After switch to next read point, no video data, stop!") break } } fos.flush() fos.close() mediaExtractor.unselectTrack(videoFrameIndex) } Copy the code
MediaMuxer solves video multiplexing, respectively solving audio MP3 and video MP4
//
val path2Save = "$filesDir/test.mp3"
mediaExtractor.extractorMedia(audioFrameIndex, path2Save)
val path2Save = "$filesDir/test.mp4"
mediaExtractor.extractorMedia(videoFrameIndex, path2Save)
/** * separates the media in the corresponding track and saves it to the specified path */
fun MediaExtractor.extractorMedia(frameIndex: Int, path2Save: String) {
val mediaMuxer = MediaMuxer(path2Save, MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4)
mediaMuxer.demuxerMedia(this, frameIndex)
mediaMuxer.release()
}
/** * writes the specified index data to the specified mixer */
fun MediaMuxer.demuxerMedia(extractor: MediaExtractor, frameIndex: Int) {
extractor.selectTrack(frameIndex)
val format = extractor.getTrackFormat(frameIndex)
val trackIndex = addTrack(format)
start()
writeMediaBuffer(extractor, format, trackIndex)
extractor.unselectTrack(frameIndex)
}
/** * the actual writing method */
private fun MediaMuxer.writeMediaBuffer(
extractor: MediaExtractor,
format: MediaFormat,
trackIndex: Int
) {
val maxMediaBufferCount: Int = format.getInteger(MediaFormat.KEY_MAX_INPUT_SIZE)
val byteBuffer = ByteBuffer.allocate(maxMediaBufferCount)
val bufferInfo = MediaCodec.BufferInfo()
while (true) {
val readSampleDataSize = extractor.readSampleData(byteBuffer, 0)
if (readSampleDataSize < 0) {
// println("index [$trackIndex] ") )
break
}
bufferInfo.size = readSampleDataSize
bufferInfo.offset = 0
bufferInfo.presentationTimeUs = extractor.sampleTime
bufferInfo.flags = extractor.sampleFlags
// println("index [$trackIndex] write data:[$readSampleDataSize]")
writeSampleData(trackIndex, byteBuffer, bufferInfo)
if(! extractor.advance()) {// println("index [$trackIndex] ") )
break}}}Copy the code
MediaMuxer unmultiplexes video, combining audio MP3 and video MP4 separately from the previous step into a new MP4
//
fun muxerAudioAndVideo(audioPath: String, videoPath: String, outPath: String) {
// Merge parsed audio and video into MP4
val audioExtractor = MediaExtractor();
audioExtractor.setDataSource(audioPath)
val audioFrameIndex = audioExtractor.findTargetStreamIndex("audio/")
val videoExtractor = MediaExtractor()
videoExtractor.setDataSource(videoPath)
val videoFrameIndex = videoExtractor.findTargetStreamIndex("video/")
if(audioFrameIndex ! = -1&& videoFrameIndex ! = -1) {
val mediaMuxer =
MediaMuxer(outPath, MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);
mediaMuxer.muxerAudioAndVideo(
audioExtractor,
videoExtractor,
audioFrameIndex,
videoFrameIndex
)
mediaMuxer.release()
} else {
println("Input audio [$audioPath: $audioFrameIndex] or video [$videoPath: $videoFrameIndex] If there is an exception, please check")
}
audioExtractor.release()
videoExtractor.release()
}
/** * Whether to reuse the specified header, video/ or audio/ */
fun MediaExtractor.findTargetStreamIndex(header: String): Int {
val trackCount = trackCount
for (i in 0 until trackCount) {
val format = getTrackFormat(i)
val mine = format.getString(MediaFormat.KEY_MIME)
if(mine? .startsWith(header)!!) { println("found target stream [$header] index[$i]. "")
return i
}
}
println("not found target stream [$header]. "")
return -1
}
/** * merge two streams */
fun MediaMuxer.muxerAudioAndVideo(
audioExtractor: MediaExtractor,
videoExtractor: MediaExtractor,
audioFrameIndex: Int,
videoFrameIndex: Int
) {
var audioTrackIndex = -1
audioExtractor.selectTrack(audioFrameIndex)
var audioFormat = audioExtractor.getTrackFormat(audioFrameIndex)
var videoTrackIndex = -1
videoExtractor.selectTrack(videoFrameIndex)
val videoFormat = videoExtractor.getTrackFormat(videoFrameIndex)
audioTrackIndex = addTrack(audioFormat)// Trace the audio channel
videoTrackIndex = addTrack(videoFormat)// Trace the video channel
start()// Start to prepare the mixture
// Write the audio stream
writeMediaBuffer(audioExtractor, audioFormat, audioTrackIndex)
// Write the video stream
writeMediaBuffer(videoExtractor, videoFormat, videoTrackIndex)
audioExtractor.unselectTrack(audioFrameIndex)
videoExtractor.unselectTrack(videoFrameIndex)
release()
}
Copy the code