我可以在MediaCodec和MediaMuxer的帮助下录制(编码)视频.接下来,我需要借助MediaCodec和MediaMuxer在视频上处理音频部分和多路复用音频.
我面临两个问题:
如何使用MediaCodec对音频进行编码.我需要在单独的线程中编码音频和视频吗?
如何将音频和视频数据传递给MediaMuxer(因为writeSampleData()方法一次只接收一种类型的数据)?
我提到了MediaMuxerTest,但它使用的是MediaExtractor.我需要使用MediaCodec,因为视频编码是使用MediaCodec完成的.如果我错了,请纠正我.
任何建议或建议都将非常有用,因为没有适用于这些新API的文档.
注意:
在一个包含不同MediaCodec
和(其他Android.Media
命名空间的东西)概念的应用程序中,我在opengl帧上生成一个视频以及PCM音调,以便我有数据发送到两个MediaCodec
编码器(发送到MediaCodec
音频的PCM块)编码器和具有surfacecolorformat的帧发送到MediaCodec
视频编码器).
你看我来了:我制作了AVC/mp4a电影.这些生成的电影在任何播放器中都很好玩
我正在使用MediaMuxer
合并视频.我知道MediaFormat
视频中的视频必须完全相同才能将它们合并在一起.但是,假设我有这些电影:
一个Happy_cat.mp4 320x20024fps1 i-frame per secondSource: Interwebz
B.Yellow background.mp4320x20024fps1 i-frame per secondSource: Me
有了MediaMuxer
,我可以将任何分割或完整版本的A混合在一起,或者B混合在一起,但我不能将A与B合并.
如果我连接A(1)+ B(1)+ A(2)+ B(2),我会看到玩A(1)的玩家然后跳到A(2),跳过B的确切持续时间.单词,它会显示猫,然后跳过猫而不显示黄色背景.如果我连接B(1)+ A(1)+ B(2)+ A(2),则相同.我会看到黄色的声音,它会跳过猫,然后会显示黄色,然后在播放猫之前停止.
知道电影需要共享相同的格式,我有一个参考电影,我可以使用它来"复制"MediaFormat参数MediaExtractor
.
我是否仅限于具有相同来源的电影,因为在将音轨添加到多路复用器之前我无法在MediaFormat中设置参数?是csd-0
和csd-1
在MediaFormat importants?因为我认为视频之间可能会有所不同.这是比较视频时我最担心的.我担心MediaMuxer
在某些本机API方法中可能会消化csd-0中的这些数据,如果基于csd-0/csd-1中的数据存在媒体配置差异,则会出错.[更新]在阅读http://bigflake.com/mediacodec/关于csd-x的部分之后,我越来越相信这是csd的一个问题.唯一的解决方案是转码所有内容.:(
来自B(1)A(1)B(2)A(2)合并的数据
B(1)黄色:
format {{max-input-size=266, durationUs=2809569, channel-count=1,
mime=audio/mp4a-latm, csd-
0=java.nio.ByteArrayBuffer[position=0,limit=2,capacity=2], sample-
rate=44100}}
format {{max-input-size=431, durationUs=3041666, csd-
1=java.nio.ByteArrayBuffer[position=0,limit=8,capacity=8], height=480,
mime=video/avc, csd- …
Run Code Online (Sandbox Code Playgroud) 我不想使用ffmpeg.目前我能够使用mp4视频复用m4a音频.我想补充的MP3音频还需要哪些MP3到M4A conversion.I能够WAV转换成M4A,但不是MP3 M4A等与下面的代码
这是我的代码.
private void convertAudio(String filename) throws IOException {
String outputpath =Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MUSIC).getPath()+"/converted.m4a";
// Set up MediaExtractor to read from the source.
MediaExtractor extractor = new MediaExtractor();
extractor.setDataSource(filename);
int trackCount = extractor.getTrackCount();
// Set up MediaMuxer for the destination.
MediaMuxer muxer;
muxer = new MediaMuxer(outputpath, MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);
// Set up the tracks.
HashMap<Integer, Integer> indexMap = new HashMap<Integer, Integer>(trackCount);
for (int i = 0; i < trackCount; i++) {
extractor.selectTrack(i);
MediaFormat format = extractor.getTrackFormat(i);
format.setString(MediaFormat.KEY_MIME, MediaFormat.MIMETYPE_AUDIO_AMR_NB);
int dstIndex = muxer.addTrack(format); …
Run Code Online (Sandbox Code Playgroud) 我需要将视频文件和音频文件合并为一个视频文件,以便:
正如我所读过的,这种合并操作的技术术语称为“混合”。
例如,假设我们有一个10秒的输入视频和一个4秒的音频文件,输出视频将是10秒(始终与输入视频相同),并且音频将播放2.5次(前2个覆盖前8秒,然后剩下4秒中的2秒)。
我找到了一种解决方案,可以将视频和音频多路复用(在此处),但遇到了多个问题:
我无法弄清楚如何在需要时循环编写音频内容。无论我尝试什么,它总是给我一个错误
输入文件必须具有特定的文件格式。否则,它可能会引发异常,或者(在极少数情况下)更糟:创建具有黑色内容的视频文件。甚至更多:有时例如可以使用“ .mkv”文件,有时则无法接受(并且两者都可以在视频播放器应用上播放)。
当前代码处理缓冲区,而不是实际持续时间。这意味着在很多情况下,即使我不这样做,我也可能会停止混合音频,并且即使视频足够长,与原始视频相比,输出视频文件的音频内容也会更短。
我尝试通过以下方法使音频的MediaExtractor每次到达末尾时都开始播放:
if (audioBufferInfo.size < 0) {
Log.d("AppLog", "reached end of audio, looping...")
audioExtractor.seekTo(0, MediaExtractor.SEEK_TO_CLOSEST_SYNC)
audioBufferInfo.size = audioExtractor.readSampleData(audioBuf, 0)
}
Run Code Online (Sandbox Code Playgroud)为了检查文件的类型,我尝试使用MediaMetadataRetriever
然后检查mime-type。我认为受支持的文档可以在文档(此处)中作为标有“编码器” 的文档获得。对此不确定。我也不知道那是哪一种MIME类型。
我还尝试重新初始化与音频有关的所有内容,但也没有用。
这是我当前的多路复用本身的代码(可在此处找到完整的示例项目):
object VideoAndAudioMuxer {
// based on: /sf/answers/2211403981/
@WorkerThread
fun joinVideoAndAudio(videoFile: File, audioFile: File, outputFile: File): Boolean {
try {
// val videoMediaMetadataRetriever = MediaMetadataRetriever()
// videoMediaMetadataRetriever.setDataSource(videoFile.absolutePath)
// val videoDurationInMs =
// videoMediaMetadataRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION).toLong()
// val videoMimeType = …
Run Code Online (Sandbox Code Playgroud) 我正在尝试使用 Android 4.3 中提供的 和 来录制音频和视频AudioRecord
。MediaCodec
但是MediaMuxer
,有时音频编码器线程会停止并且不再进行编码。结果是,mp4 文件损坏,因为复用器未接收任何编码的音频帧。在我的三星 Galaxy Note 3 上,它可以正常工作 99%,但在我的索尼 Xperia Z1 上,编码线程总是卡住。我真的不知道是什么原因,也许有人可以帮助我优化我的代码:
录音机.java
package com.cmdd.horicam;
import java.nio.ByteBuffer;
import android.media.AudioFormat;
import android.media.AudioRecord;
import android.media.MediaCodec;
import android.media.MediaCodecInfo;
import android.media.MediaFormat;
import android.media.MediaRecorder;
import android.os.Looper;
import android.util.Log;
public class AudioRecorder implements Runnable {
public static final String TAG = "AudioRecorder";
public static final boolean VERBOSE = false;
public MovieMuxerAudioHandler mAudioHandler;
// audio format settings
public static final String MIME_TYPE_AUDIO = "audio/mp4a-latm";
public static final int …
Run Code Online (Sandbox Code Playgroud) 我正在尝试从一系列位图创建电影。我想以 API 19 为目标,但也可以利用 API 21(如果它在设备上可用)。
我一直在阅读 bigflake CTS 测试,尤其是这里的EncodeAndMux 和 EncodeDecodeTest
我想使用 MediaCodec 和 MediaMuxer 类,而不是 FFMpeg 或 Jcodec 等。
如果您能指出我哪里出错以及如何解决,我将不胜感激。我是 Android 新手,为此苦苦挣扎了好几天!我正在三星 Galaxy Note 3 上进行测试
更新:我能够访问 EOS,但在尝试释放编码器时出现编解码器错误。
这是更新后的代码:
public void createMovie(View view) {
Log.v(TAG,"CREATING MOVIE");
//1. Prepare the encoder and the GPUImageView
try {
prepareEncoder();
presentationTime = 0;
int j = 0;
for (int i = firstImageIndex; i <= lastImageIndex; i++) {
Log.v(TAG, "inLoop: " + i);
//1
durationInNanosec = (long) ((float) durations.get(j) * 100000); …
Run Code Online (Sandbox Code Playgroud) 我目前有两个单独的媒体提取器和编解码器,用于将每个单独的样本分解为ByteBuffer
s。然后我将每个样本存储到两个short
数组中。然后我调用我的混合函数,它将两个样本合并为一个short[]
,如果我short[]
用AudioTrack
它来播放,结果会很好,两种声音都可以根据需要同时播放。
但是,我真正想做的是使用MediaMuxer
将我的新short[]
文件转换回 mp4 音频文件并将其存储到设备以供以后播放。有人可以帮我弄清楚我做错了什么吗?
这是我拥有的一些代码......正如你所看到的,我注释掉了AudioTrack
,这就是我试图将short[]
背面变成 的地方,ByteBuffer
所以我可以使用媒体复用器来创建音频文件。这给我的结果是一个新的音频文件,它是存储在我设备上的正确名称和总长度……但是当我尝试播放它时……它在几分之一秒内从头跳到尾,实际上并没有播放和音频。
songOutPath = Environment.getExternalStorageDirectory()+"/My Folder/song.raw";
muxer = new MediaMuxer(songOutPath, MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);
mTrackIndex = muxer.addTrack(format);
muxer.start();
mMuxerStarted = true;
MediaCodec.BufferInfo info = new MediaCodec.BufferInfo();
final long timeoutUs = 5000;
boolean sawInputEOS = false;
boolean sawOutputEOS = false;
int noOutputCounter = 0;
MediaCodec.BufferInfo info2 = new MediaCodec.BufferInfo();
final long timeoutUs2 = 5000;
boolean sawInputEOS2 = false;
boolean sawOutputEOS2 …
Run Code Online (Sandbox Code Playgroud) 我使用 MediaMuxer 混合音频和无线电数据,数据来自两个编码器,流程正确,我得到输出并播放。但是 MediaMuxer 在 writeSampleData 时可能会因为错误而失败:
E/MPEG4Writer: timestampUs 21932611 < lastTimestampUs 22055361 for Video track
10-14 14:23:41.580 20089-20230/org.cocos2dx.simplegame E/AndroidRuntime: FATAL EXCEPTION: MediaMuxer
10-14 14:23:41.580 20089-20230/org.cocos2dx.simplegame E/AndroidRuntime: Process: org.cocos2dx.simplegame, PID: 20089
10-14 14:23:41.580 20089-20230/org.cocos2dx.simplegame E/AndroidRuntime: java.lang.IllegalStateException: writeSampleData returned an error
10-14 14:23:41.580 20089-20230/org.cocos2dx.simplegame E/AndroidRuntime: at android.media.MediaMuxer.nativeWriteSampleData(Native Method)
10-14 14:23:41.580 20089-20230/org.cocos2dx.simplegame E/AndroidRuntime: at android.media.MediaMuxer.writeSampleData(MediaMuxer.java:334)
10-14 14:23:41.580 20089-20230/org.cocos2dx.simplegame E/AndroidRuntime: at com.duapps.durecorder.muxer.DuMediaMuxer.handleMessage(DuMediaMuxer.java:53)
10-14 14:23:41.580 20089-20230/org.cocos2dx.simplegame E/AndroidRuntime: at android.os.Handler.dispatchMessage(Handler.java:102)
10-14 14:23:41.580 20089-20230/org.cocos2dx.simplegame E/AndroidRuntime: at android.os.Looper.loop(Looper.java:136)
10-14 14:23:41.580 20089-20230/org.cocos2dx.simplegame E/AndroidRuntime: at android.os.HandlerThread.run(HandlerThread.java:61)
Run Code Online (Sandbox Code Playgroud)
我看到MPEG4Writer,错误的根本原因是视频的时间戳,它让MediaMuxer运行到IllegalState。经过大量测试后,我知道视频和音频时间戳都可能出现错误,并且当我更改音频采样率时,重复率会发生变化。
当我只录制音频或广播时,错误不会再次发生。
有人可以给我一些建议吗?
我有将 wav 转换为 m4a 的工作代码。无论如何通过修改我现有的代码将 mp3 转换为 m4a。我不想使用 ffmpeg 或本机代码对此。下面的函数适用于 wav 到 m4a 的转换,但不是适用于 mp3 到 m4a
public void convertAudio(final String filename) {
final String AUDIO_RECORDING_FILE_NAME = Config.mp3Audio; // Input PCM file
final String COMPRESSED_AUDIO_FILE_NAME = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MUSIC).getPath()
+ "/convertedmp4.m4a"; // Output MP4/M4A file
final String COMPRESSED_AUDIO_FILE_MIME_TYPE = "audio/mp4a-latm";
final int COMPRESSED_AUDIO_FILE_BIT_RATE = 320000; // 64kbps
final int SAMPLING_RATE = 22050;
final int BUFFER_SIZE = 22050;
final int CODEC_TIMEOUT_IN_MS = 5000;
String LOGTAG = "CONVERT AUDIO";
try {
File inputFile = …
Run Code Online (Sandbox Code Playgroud) 使用 FFMPEG 视频处理库和 MediaCodec 处理 Lottie 动画有一些独特的概念。在这方面,我想从 Lottie 动画制作视频并将该视频叠加在其他原始视频上。
但问题是我无法从 Lottie 动画制作具有透明背景的视频。因此,我使用 MediaCodec 和 MediaMuxer 从 Lottie 动画制作了简单的视频,它从 Lottie Drawable 中一帧一帧地将其附加到视频(Lottie Video)。这是有关此概念的链接 - https://engineering.21buttons.com/how-to-generate-videos-using-lottie-in-android-2db6ecceb2a
然后我使用 FFmpeg 库将此视频叠加到原始视频上。这里 FFmpeg 执行两个任务,首先它在 Lottie Video 中制作透明背景,其次它将这个 Lottie Video 覆盖在原始视频之上。
这里实际的问题就出来了,FFmpeg 在处理 25 秒的视频时需要超过 8 到 9 分钟,所以我想找到这个问题的解决方案,因为我的时间限制只有 1 到 2 分钟。任何人都有解决方案或实现此概念的新IDE,那么请告诉我,我将不胜感激。
android ×10
mediamuxer ×10
audio ×5
video ×3
mediacodec ×2
ffmpeg ×1
lottie ×1
m4a ×1
mp3 ×1
mp4 ×1