标签: mediacodec

从Surface编码时,编码器在Adreno GPU上崩溃

我一直在努力解决这个问题一个多星期,而且很可能是高通GPU /硬件视频编码器中的一个错误.由于我们被迫发布应用程序,他们的开发者论坛没有提供任何反馈,我也在这里发布,希望有人能够提供一些线索,甚至更好的解决方法,以便编码器中的错误是没有触发.

应用程序从Surface编码.当某些图像渲染到表面时,编码器在同一位置失败(100%)(当前编码的帧是关键帧时).崩溃时编码器的Logcat输出是(最后一行以非常高的速率重复):

11-26 11:41:33.312: E/OMX-VENC-720p(25949): ERROR: async_msg_process() - Error statuscode = 1
11-26 11:41:33.312: E/ACodec(29317): [OMX.qcom.video.encoder.avc] ERROR(0x80001009)
11-26 11:41:33.312: E/MediaCodec(29317): Codec reported an error. (omx error 0x80001009, internalError -2147483648)
11-26 11:41:33.362: E/OMX-VENC-720p(25949): ERROR: venc_use_buf:set input buffer failed 
11-26 11:41:33.362: E/OMX-VENC-720p(25949): ERROR: in dev_use_buf
11-26 11:41:33.362: E/OMX-VENC-720p(25949): ERROR: empty_buffer_done() failed!
11-26 11:41:33.372: E/OMX-VENC-720p(25949): m_fbd_count at o/p flush = 306
11-26 11:41:33.372: E/OMX-VENC-720p(25949): m_etb_count at i/p flush = 313
11-26 11:41:33.372: E/OMX-VENC-720p(25949): ERROR: ioctl VEN_IOCTL_CMD_FILL_OUTPUT_BUFFER failed
11-26 11:41:33.372: E/OMX-VENC-720p(25949): …
Run Code Online (Sandbox Code Playgroud)

android video-encoding mediacodec

66
推荐指数
1
解决办法
2856
查看次数

使用MediaCodec和MediaMuxer对视频进行编码和复用

我正在开发一个应用程序,我解码视频并替换某些帧并使用MediaMuxer和重新编码MediaCodec.如果我不替换任何帧(除了1080p视频,我将在下面解释),该应用程序可以工作,但是当我这样做时,替换后的帧会像素化,视频会不稳定.

此外,当我尝试使用1920x1080视频的应用程序时,我得到一个奇怪的输出,其中视频没有显示任何内容,直到我滚动到视频的开头,然后视频开始显示(但具有之前提到的相同问题)编辑后的像素化.

以下是我配置编码器的方法:

Video_format.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, interval);
Video_format.setInteger(MediaFormat.KEY_BIT_RATE, bitRate);
Video_format.setInteger(MediaFormat.KEY_FRAME_RATE, frameRate);
Video_format.setInteger(MediaFormat.KEY_MAX_INPUT_SIZE, 0);
int color_format=MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420SemiPlanar;
Video_format.setInteger(MediaFormat.KEY_COLOR_FORMAT, color_format);

encoder.configure(Video_format, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
Run Code Online (Sandbox Code Playgroud)

总而言之,我有两个问题:

1-修改帧后的像素化帧和不连贯的视频.

2-损坏的1920x1080视频,除非我滚动到开头.

编辑

这是一个未经编辑的1080p视频示例,当我在VLC上播放并在手机上播放不正确时会显示绿屏,除非我滚动开始,现在奇怪地在YouTube上正常工作,除了开始时的绿框

这是一个720p视频样本,在开始时也使用绿色框架进行编辑,并在编辑后清除像素化和滞后

这是我用来解码重新编码的代码:

do{
  Bitmap b1;

  if(edited_frames.containsKey(extractor.getSampleTime()))
    b1=BitmapFactory.decodeFile(edited_frames.get(extractor.getSampleTime()));
  else
    b1=decode(extractor.getSampleTime(),Preview_width,Preview_Height);

  if(b1==null) continue;

  Bitmap b_scal=Bitmap.createScaledBitmap(b1, Preview_width, Preview_Height, false);
  if(b_scal==null) continue;
  encode(b_scal, encoder, muxer, videoTrackIndex);
  lastTime=extractor.getSampleTime();
}while(extractor.advance());
Run Code Online (Sandbox Code Playgroud)

解码方法:

private Bitmap decode(final long time,final int width,final int height){
  MediaFormat newFormat = codec.getOutputFormat();
  Bitmap b = null;
  final int TIMEOUT_USEC = 10000;
  ByteBuffer[] …
Run Code Online (Sandbox Code Playgroud)

video android mediacodec mediamuxer

61
推荐指数
1
解决办法
6672
查看次数

在android中添加水印位图:4.3的MediaMuxer或ffmpeg

这是我的场景:

  • 从网上下载avi电影
  • 打开位图资源
  • 在背景中的所有帧上将此位图叠加在电影的底部
  • 将视频保存在extarnal存储上
  • 视频长度通常为15秒

这可能是使用MediaMuxer实现的吗?很高兴收到有关此事的任何信息

我一直在寻找http://bigflake.com/mediacodec/#DecodeEditEncodeTest(谢谢@fadden),它说:

"解码帧并将其复制到ByteBuffer, glReadPixels()在Nexus 5上大约需要8ms,足够快,足以跟上30fps的输入速度,但将其作为PNG保存到磁盘所需的额外步骤是昂贵的(大约半秒钟) "

所以几乎1秒/帧是不可接受的.根据我的想法,一种方法是将每个帧保存为PNG,打开它,在其上添加位图叠加然后保存它.然而,这将花费大量时间来完成.

我想知道是否有办法做这样的事情:

  1. 从外部存储打开视频文件
  2. 开始解码它
  3. 每个解码的帧将被改变,内存中的位图覆盖
  4. 帧被发送到编码器.

在iOS上,我看到有一种方法可以将原始音频+原始视频+图像添加到容器中,然后对整个事物进行编码...

我应该切换到ffmpeg吗?ffmpeg的稳定性和兼容性如何?我是否冒着与Android 4.0+设备兼容的问题?有没有办法用ffmpeg来实现这个?我是这个领域的新手,还在做研究.


多年后编辑:
自问题以来已过去多年,并且ffmpeg在许可方面很难添加到商业软件中.这是如何演变的?较新版本的android在默认sdk上更有能力吗?


稍后编辑一段时间

我发布了一些负面投票信息作为答案,因此我将编辑原始问题.这是一个很棒的库,从我的测试中确实将水印应用于视频并使用进度回调进行处理,这使得向用户显示进度变得更加容易,并且还使用默认的android sdks.https://github.com/MasayukiSuda/Mp4Composer-android

该库使用Android MediaCodec API生成Mp4电影,并应用滤镜,缩放和旋转Mp4.

示例代码,可能如下所示:

new mp4Composer(sourcePath, destinationPath)
        .filter(new GlWatermarkFilter(watermarkBitmap)
        .listener(){
              @Override 
              private void onProgress(double value){}

              @Override 
              private void onCompleted(double value){
                  runOnUiThread( () ->{
                     showSneakbar
                  }
              }

              @Override 
              private void onCancelled(double value){}

              @Override 
              private void onFailed(Exception e){}

        }).start();
Run Code Online (Sandbox Code Playgroud)

在模拟器上进行测试,似乎在android 8+上正常工作,而在旧版本上生成黑色视频文件.但是,在真实设备上进行测试似乎有效.

mp4 android ffmpeg mediacodec mediamuxer

31
推荐指数
3
解决办法
1万
查看次数

如何在没有MediaExtractor的情况下为H264使用MediaCodec

我需要在没有MediaExtractor的情况下使用MediaCodec,我正在使用FileInputStream读取文件.目前它不工作,它在屏幕上显示绿色的乱码图像.

这是完整的源代码:

FileInputStream in = new FileInputStream("/sdcard/sample.ts");

String mimeType = "video/avc";
MediaCodec decoder = MediaCodec.createDecoderByType(mimeType);
MediaFormat format = MediaFormat.createVideoFormat(mimeType, 1920, 1080);

byte[] header_sps = { 0, 0, 0, 1, 103, 100, 0, 40, -84, 52, -59, 1, -32, 17, 31, 120, 11, 80, 16, 16, 31, 0, 0, 3, 3, -23, 0, 0, -22, 96, -108 };
byte[] header_pps = { 0, 0, 0, 1, 104, -18, 60, -128 };
format.setByteBuffer("csd-0", ByteBuffer.wrap(header_sps));
format.setByteBuffer("csd-1", ByteBuffer.wrap(header_pps));
format.setInteger(MediaFormat.KEY_MAX_INPUT_SIZE, 1920 * 1080);
format.setInteger("durationUs", 63446722); …
Run Code Online (Sandbox Code Playgroud)

android transport-stream h.264 stagefright mediacodec

24
推荐指数
2
解决办法
2万
查看次数

MediaCodec getInputImage在某些设备上返回null

我想通过设置颜色格式使用MediaCodec进行编码COLOR_FormatYUV420Flexible.我的输入缓冲区是yuv420p.当我像这样输入缓冲区时:

    int inputBufferIndex = mEncoder.dequeueInputBuffer(-1);
    mCurrentBufferIndex = inputBufferIndex;
    if (inputBufferIndex >= 0) {
        ByteBuffer inputBuffer = inputBuffers[inputBufferIndex];
        //if(VERBOSE)
            Log.i(TAG,"pos:"+inputBuffer.position()+"\tlimit:"+inputBuffer.limit());
        inputBuffer.clear();
        return inputBuffer;
    }
Run Code Online (Sandbox Code Playgroud)

但有些设备颜色错误.所以我试试这个:

    int inputBufferIndex = mEncoder.dequeueInputBuffer(-1);
    mCurrentBufferIndex = inputBufferIndex;
    if (inputBufferIndex >= 0) {
        Image img = mEncoder.getInputImage(inputBufferIndex);
        if(img==null)
            return null;
        //mCurrentInputPlanes = img.getPlanes();
        ByteBuffer buffers[]={img.getPlanes()[0].getBuffer(),
                img.getPlanes()[1].getBuffer(),
                img.getPlanes()[2].getBuffer()};
Run Code Online (Sandbox Code Playgroud)

我将缓冲区填充到YUV通道.它可以在某些设备上运行.但是当调用getInputImage时,moto X pro和huawei P7变为null.文档说图像不包含原始数据.但它也提到COLOR_FormatYUV420Flexible自API 21以来的支持.所以我应该如何解决这个问题.

android encode mediacodec

23
推荐指数
1
解决办法
451
查看次数

Android MediaCodec AAC编码器

我使用MediaCodecAndroid SDK提供的类,因为API级别16与OMX.SEC.aac.enc编码器一起将音频编码为文件.我从AudioRecord课堂上得到了音频输入.我的AudioRecord类实例配置如下:

bufferSize = AudioRecord.getMinBufferSize(44100, AudioFormat.CHANNEL_IN_STEREO, AudioFormat.ENCODING_PCM_16BIT);
recorder = new AudioRecord(MediaRecorder.AudioSource.MIC, 44100, AudioFormat.CHANNEL_IN_STEREO, AudioFormat.ENCODING_DEFAULT, bufferSize);
Run Code Online (Sandbox Code Playgroud)

我能够从AudioRecord实例播放原始数据,因此问题不在那里.

我将AudioRecord实例的输出写入ByteBuffer实例并将其传递给编码器的可用输入缓冲区.编码器的输出被写入SD卡上的文件.

这些是我的MediaCodec实例的配置参数:

codec = MediaCodec.createEncoderByType("audio/mp4a-latm");
MediaFormat format = new MediaFormat();
format.setString(MediaFormat.KEY_MIME, "audio/mp4a-latm");
format.setInteger(MediaFormat.KEY_BIT_RATE, 64 * 1024);
format.setInteger(MediaFormat.KEY_CHANNEL_COUNT, 2);
format.setInteger(MediaFormat.KEY_SAMPLE_RATE, 44100);
format.setInteger(MediaFormat.KEY_AAC_PROFILE, MediaCodecInfo.CodecProfileLevel.AACObjectHE);
codec.configure(format, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
Run Code Online (Sandbox Code Playgroud)

VLC告诉我,我的aac文件中没有流.该命令FFMPEG -i @filename@给出了以下错误:处理输入时找到无效数据.我测试过的所有媒体播放器都无法播放我的文件.

为什么我无法播放我的文件?我没有收到OpenMAX错误,LogCat应用程序在编码时不会崩溃.我写了一个视频编码器,它的工作原理与之相同.

这是将数据从AudioRecord实例读取到缓冲区的代码:

    new Thread() {
        public void run() { …
Run Code Online (Sandbox Code Playgroud)

android aac audiorecord openmax mediacodec

22
推荐指数
1
解决办法
1万
查看次数

SurfaceTexture的onFrameAvailable()方法总是被调用太晚了

我正在尝试使用以下MediaExtractor示例:

http://bigflake.com/mediacodec/ - ExtractMpegFramesTest.java(需要4.1,API 16)

我遇到的问题是outputSurface.awaitNewImage(); 似乎总是抛出RuntimeException("frame wait timed out"),每当mFrameSyncObject.wait(TIMEOUT_MS)调用超时时抛出它.无论我设置什么TIMEOUT_MS,onFrameAvailable()总是在超时发生后立即调用.我尝试了50毫秒和30000毫秒,它是相同的.

似乎onFrameAvailable()在线程繁忙时无法进行调用,并且一旦超时发生并结束线程代码执行,它就可以解析onFrameAvailable()调用.

有没有人设法让这个例子工作,或者知道MediaExtractor应该如何使用GL纹理?

编辑:在使用API​​ 4.4和4.1.1的设备上尝试了这一点,两者都发生了同样的情况.

编辑2:

得益于fadden 4.4.问题是ExtractMpegFramesWrapper.runTest()调用的方法th.join();阻塞了主线程并阻止了onFrameAvailable()调用的处理.一旦我评论th.join();它就适用于4.4.我想也许ExtractMpegFramesWrapper.runTest()本身应该在另一个线程上运行,所以主线程没有被阻止.

4.1.2调用时还有一个小问题codec.configure(),它给出了错误:

A/ACodec(2566): frameworks/av/media/libstagefright/ACodec.cpp:1041 CHECK(def.nBufferSize >= size) failed.
A/libc(2566): Fatal signal 11 (SIGSEGV) at 0xdeadbaad (code=1), thread 2625 (CodecLooper)
Run Code Online (Sandbox Code Playgroud)

通过在通话前添加以下内容我解决了这个问题:

format.setInteger(MediaFormat.KEY_MAX_INPUT_SIZE, 0);
Run Code Online (Sandbox Code Playgroud)

然而,我现在在4.1.1(Galaxy S2 GT-I9100)和4.1.2(三星Galaxy Tab GT-P3110)上的问题是它们都始终将info.size设置为0以用于所有帧.这是日志输出:

loop
input buffer not available
no output from decoder available
loop
input …
Run Code Online (Sandbox Code Playgroud)

android opengl-es mediacodec mediaextractor

22
推荐指数
1
解决办法
1万
查看次数

PCM - > AAC(编码器) - > PCM(解码器)实时正确优化

我正在努力实施

AudioRecord (MIC) ->

PCM -> AAC Encoder
AAC -> PCM Decode

-> AudioTrack??  (SPEAKER)
Run Code Online (Sandbox Code Playgroud)

MediaCodec在Android 4.1+(API16).

首先,我成功(但不知道正确优化)实现PCM -> AAC EncoderMediaCodec为如下预期

private boolean setEncoder(int rate)
{
    encoder = MediaCodec.createEncoderByType("audio/mp4a-latm");
    MediaFormat format = new MediaFormat();
    format.setString(MediaFormat.KEY_MIME, "audio/mp4a-latm");
    format.setInteger(MediaFormat.KEY_CHANNEL_COUNT, 1);
    format.setInteger(MediaFormat.KEY_SAMPLE_RATE, 44100);
    format.setInteger(MediaFormat.KEY_BIT_RATE, 64 * 1024);//AAC-HE 64kbps
    format.setInteger(MediaFormat.KEY_AAC_PROFILE, MediaCodecInfo.CodecProfileLevel.AACObjectHE);
    encoder.configure(format, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
    return true;
}
Run Code Online (Sandbox Code Playgroud)

INPUT:PCM比特率= 44100(Hz)x 16(比特)×1(等值)= 705600比特/秒

输出:AAC-HE比特率= 64 x 1024(比特)= 65536比特/秒

因此,数据大小近似被压缩x11,我通过观察日志确认了这一点

  • AudioRecoder:读取4096字节
  • AudioEncoder:369字节编码

数据大小近似压缩x11,到目前为止一直很好.

现在,我有一个UDP服务器来接收编码数据,然后解码它.

解码器配置文件设置如下:

private …
Run Code Online (Sandbox Code Playgroud)

android aac pcm audiorecord mediacodec

21
推荐指数
3
解决办法
2万
查看次数

如何使用Android MediaCodec生成AAC ADTS基本流

我要做的是:使用Android的MediaCodec将原始PCM音频样本编码为原始AAC文件.

遇到的问题:当我使用FFMPEG将生成的原始AAC文件打包到M4A容器中时,FFMPEG抱怨文件中缺少编解码器参数.

细节:

由于我找不到生成输出AAC文件的音频编码器的任何MediaCodec示例代码,我尝试将视频编码器修改为音频编码器.原始代码在这里:source_code

我配置了这样的音频编码器:

    mEncoderFormat = MediaFormat.createAudioFormat("audio/mp4a-latm", (int)mAudioSampleRate, 2);

    // redundant?
    mEncoderFormat.setString(MediaFormat.KEY_MIME, "audio/mp4a-latm");
    mEncoderFormat.setInteger(MediaFormat.KEY_AAC_PROFILE, 
                      MediaCodecInfo.CodecProfileLevel.AACObjectELD);
    mEncoderFormat.setInteger(MediaFormat.KEY_SAMPLE_RATE, kSampleRates);
    mEncoderFormat.setInteger(MediaFormat.KEY_BIT_RATE, kBitRates);
    mEncoderFormat.setInteger(MediaFormat.KEY_CHANNEL_COUNT, 2);
    testEncoderWithFormat("audio/mp4a-latm", mEncoderFormat);

    try {
        codec.configure(
                mEncoderFormat,
                null /* surface */,
                null /* crypto */,
                MediaCodec.CONFIGURE_FLAG_ENCODE);
    } catch (IllegalStateException e) {
        Log.e(TAG, "codec '" + componentName + "' failed configuration.");
        return;
    }
    Log.d(TAG, "  testEncoder configured with format = " + format);
Run Code Online (Sandbox Code Playgroud)

然后我给编码器每帧提供10ms的PCM采样.编码器获取每个帧,生成一个比特流帧,然后将比特流写入FileOutputStream.循环一直持续到输入文件结束.

代码运行完成.我'adb pull'将生成的AAC文件从设备传送到我的PC,并使用FFMPEG来读取它.下面是命令和错误FFMPEG吐出:

$ ffmpeg -f aac -i BlessedNoColor_nexus7_api18.aac
ffmpeg version N-45739-g04bf2e7 …
Run Code Online (Sandbox Code Playgroud)

audio encoding android mediacodec

20
推荐指数
1
解决办法
2万
查看次数

使用MediaCodec和MediaMuxer的图像到视频

我有一堆本地图像保存为jpeg文件.我的图像是使用CameraPreview捕获的,而PreviewFormat是默认值:NV21.我想从固定数量的图像生成一个小视频.

我不打算使用FFMpeg因为它需要NDK并且会引入兼容性问题.

MediaCodec和MediaMuxer似乎很有效,但网上没有一个可行的解决方案.

有一些参考资料导致我目前的解决方案.

1. EncodeAndMuxTest:http://bigflake.com/mediacodec/EncodeAndMuxTest.java.txt

这个是由法登写的.它非常适合我的需要,除了他使用的是createInputSurface而不是queueInputBuffer.

2. 将位图数组转换为YUV(YCbCr NV21)

我按照这个答案进行转换./sf/answers/1198188981/

3. 使用MediaCodec将一系列图像保存为视频

这个问题看起来与我的很相似,但我不打扰使用MediaMuxer.

我的代码如下:

public class EncodeAndMux extends Activity {
private static final String TAG = "EncodeAndMuxTest";

private static final boolean VERBOSE = false;

private static final File OUTPUT_DIR = Environment
        .getExternalStorageDirectory();

private static final String MIME_TYPE = "video/avc";

private static final int FRAME_RATE = 10;
// 10 seconds between I-frames
private static final int IFRAME_INTERVAL = 10;

private static final int NUM_FRAMES …
Run Code Online (Sandbox Code Playgroud)

android mediacodec

17
推荐指数
1
解决办法
1万
查看次数