Я пытаюсь использовать следующий пример MediaExtractor:
http://bigflake.com/mediacodec/- ExtractMpegFramesTest.java(требуется 4.1, API 16)
Проблема заключается в том, что outputSurface.awaitNewImage(); похоже, всегда бросает RuntimeException ( "время ожидания кадра" ), которое вызывается всякий раз, когда вызов mFrameSyncObject.wait(TIMEOUT_MS)
истекает. Независимо от того, что я установил TIMEOUT_MS
, onFrameAvailable()
всегда вызывается сразу после истечения таймаута. Я пробовал с 50ms и с 30000ms, и это то же самое.
Похоже, вызов onFrameAvailable()
не может быть выполнен, пока поток занят, и как только произойдет таймаут, который завершит выполнение кода потока, он может разобрать вызов onFrameAvailable()
.
Кто-нибудь смог заставить этот пример работать или знает, как MediaExtractor должен работать с текстурами GL?
Изменить: попробовал это на устройствах с API 4.4 и 4.1.1, и то же самое происходит на обоих.
Изменить 2:
Получил работу над 4.4 благодаря fadden. Проблема заключалась в том, что метод 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)
Что я решил, добавив следующее перед вызовом:
format.setInteger(MediaFormat.KEY_MAX_INPUT_SIZE, 0);
Однако проблема, с которой я столкнулся как в 4.1.1 (Galaxy S2 GT-I9100), так и в 4.1.2 (Samsung Galaxy Tab GT-P3110), заключается в том, что оба они всегда устанавливают значение info.size равным 0 для всех кадров. Вот вывод журнала:
loop
input buffer not available
no output from decoder available
loop
input buffer not available
no output from decoder available
loop
input buffer not available
no output from decoder available
loop
input buffer not available
no output from decoder available
loop
submitted frame 0 to dec, size=20562
no output from decoder available
loop
submitted frame 1 to dec, size=7193
no output from decoder available
loop
[... skipped 18 lines ...]
submitted frame 8 to dec, size=6531
no output from decoder available
loop
submitted frame 9 to dec, size=5639
decoder output format changed: {height=240, what=1869968451, color-format=19, slice-height=240, crop-left=0, width=320, crop-bottom=239, crop-top=0, mime=video/raw, stride=320, crop-right=319}
loop
submitted frame 10 to dec, size=6272
surface decoder given buffer 0 (size=0)
loop
[... skipped 1211 lines ...]
submitted frame 409 to dec, size=456
surface decoder given buffer 1 (size=0)
loop
sent input EOS
surface decoder given buffer 0 (size=0)
loop
surface decoder given buffer 1 (size=0)
loop
surface decoder given buffer 0 (size=0)
loop
surface decoder given buffer 1 (size=0)
loop
[... skipped 27 lines all with size=0 ...]
surface decoder given buffer 1 (size=0)
loop
surface decoder given buffer 0 (size=0)
output EOS
Saving 0 frames took ? us per frame // edited to avoid division-by-zero error
Таким образом, изображения не будут сохранены. Однако тот же код и видео работают на 4.3. Видео, которое я использую, является файлом .mp4 с видеокодеком "H264 - MPEG-4 AVC (avc1)" и аудиокодеком MPEG AAAC Audio (mp4a).
Я также пробовал другие видеоформаты, но они, кажется, умирают еще раньше на 4.1.x, а оба работают на 4.3.
Изменить 3:
Я сделал то, что вы предлагали, и, похоже, правильно сохраняет изображения фреймов. Спасибо.
Что касается KEY_MAX_INPUT_SIZE, я попытался не устанавливать или устанавливать его на 0, 20, 200,... 200000000, все с тем же результатом info.size = 0.
Теперь я не могу установить рендер в SurfaceView или TextureView на мой макет. Я попытался заменить эту строку:
mSurfaceTexture = new SurfaceTexture(mTextureRender.getTextureId());
с этим, где surfaceTexture
является SurfaceTexture, определенным в моем xml-макете:
mSurfaceTexture = textureView.getSurfaceTexture();
mSurfaceTexture.attachToGLContext(mTextureRender.getTextureId());
но он вызывает странную ошибку с getMessage()==null
во второй строке. Я не мог найти другого способа заставить его использовать какой-либо вид. Как я могу изменить декодер для отображения фреймов на Surface/SurfaceView/TextureView вместо их сохранения?