Android: MPEG4Writer no se puede iniciar al usar OMXCodec como MediaSource
c++ android-ndk (2)
MPEG4Writer
codificar un video desde un buffer de matriz de bytes y para hacerlo estoy usando MPEG4Writer
API desde código nativo.
OMXCodec
mi clase MediaSource
personalizada para proporcionar los datos y la OMXCodec
con OMXCodec
para dársela a MPEG4Writer
:
sp<MediaSource> mVideoEncoder = OMXCodec::Create(client.interface(), omxEncMeta, true, mVideoOutSource);
mVideoEncoder->start();
mVideoOutSource
es mi clase MediaSource
personalizada, omxEncMeta
es la siguiente:
int32_t colorFormat = OMX_COLOR_FormatYUV420SemiPlanar;
int32_t width = 480;
int32_t height = 360;
int32_t frameRate = 24;
int32_t bitRate = 500 * 1024;
int32_t iFrameInterval = 1;
sp<MetaData> omxEncMeta = new MetaData;
omxEncMeta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_AVC);
omxEncMeta->setInt32(kKeyColorFormat, colorFormat);
omxEncMeta->setInt32(kKeyWidth, width);
omxEncMeta->setInt32(kKeyHeight, height);
omxEncMeta->setInt32(kKeyStride, width);
omxEncMeta->setInt32(kKeySliceHeight, height);
omxEncMeta->setInt32(kKeyFrameRate, frameRate);
omxEncMeta->setInt32(kKeySampleRate, frameRate);
omxEncMeta->setInt32(kKeyBitRate, bitRate);
omxEncMeta->setInt32(kKeyIFramesInterval, iFrameInterval);
pero cuando llamo al método start()
, devuelve el código de error UNKNOWN_ERROR
.
En cambio, si trato de darle a MPEG4Writer
directamente mi MediaSource
personalizado (sin envolverlo con OMXCodec
se inicia con éxito pero finalmente dejará de grabar con el error Missing codec specific data
(después de 12 fotogramas), y creo que es porque mi costumbre MediaSource
proporciona solo información sobre los marcos reales, pero nada sobre el formato del códec.
Estoy seguro de que me falta algo con OMXCodec
, pero no puedo entender qué ... ¿Hay alguien que pueda proporcionarme un ejemplo MediaSource
de un MediaSource
personalizado para la codificación? ¿O darme algunas pistas sobre por qué esto no funciona en absoluto?
Si necesita más información, solo pregunte, ¡gracias!
EDITAR : Estoy desarrollando esto contra API 14 así que no me sugiera que use MediaCodec
desde API 16 :)
EDITAR : Así es como estoy comenzando MPEG4Writer
:
int32_t outputFormat = OUTPUT_FORMAT_MPEG_4;
int64_t startTimeUs = systemTime() / 1000;
int32_t totalBitRate = bitRate;
sp<MetaData> meta = new MetaData;
meta->setInt64(kKeyTime, startTimeUs);
meta->setInt32(kKeyFileType, outputFormat);
meta->setInt32(kKeyBitRate, totalBitRate);
sp<MPEG4Writer> mWriter = new MPEG4Writer("/sdcard/encode_manual.mp4");
mWriter->addSource(mVideoEncoder);
status_t error = mWriter->start(meta.get());
if (error != OK) {
LOGE("Writer NOT started! %x", error);
} else {
LOGI("Writer started!");
}
Este es el resultado de logcat ( adb logcat OMXClient:V OMXCodec:V *:W
):
W/ResourceType( 370): Skipping entry 0x7f04002f in package table 0 because it is not complex!
E/ ( 4127): Can''t open file for reading
E/ ( 4127): Can''t open file for reading
E/OMX-VENC-720p( 155):
E/OMX-VENC-720p( 155): omx_video(): Inside Constructor()
E/OMX-VENC-720p( 155):
E/OMX-VENC-720p( 155): omx_venc(): Inside component_init()
E/OMX-VENC-720p( 155): bool venc_dev::venc_validate_profile_level(OMX_U32*, OMX_U32*): Returning with eProfile = 1Level = 4
E/OMX-VENC-720p( 155):
E/OMX-VENC-720p( 155): bool venc_dev::venc_open(OMX_U32)(): Init Profile/Level setting success
E/OMX-VENC-720p( 155): vidc.venc.debug.sliceinfo value is 0
E/OMX-VENC-720p( 155):
E/OMX-VENC-720p( 155): Component_init return value = 0x0
E/OMX-VENC-720p( 155):
E/OMX-VENC-720p( 155): WARNING: Requested i/p bufsize[40960],Driver''s updated i/p bufsize = 262144
E/OMX-VENC-720p( 155): bool venc_dev::venc_validate_profile_level(OMX_U32*, OMX_U32*): Returning with eProfile = 1Level = 256
E/OMX-VENC-720p( 155):
E/OMX-VENC-720p( 155): bool venc_dev::venc_set_param(void*, OMX_INDEXTYPE)(): Profile/Level setting success
E/OMX-VENC-720p( 155): bool venc_dev::venc_validate_profile_level(OMX_U32*, OMX_U32*): Returning with eProfile = 1Level = 64
E/OMX-VENC-720p( 155): Calling set level (Framerate) with 15
E/OMX-VENC-720p( 155): bool venc_dev::venc_validate_profile_level(OMX_U32*, OMX_U32*): Returning with eProfile = 1Level = 64
E/OMX-VENC-720p( 155): Calling set level (Bitrate) with 15
E/OMX-VENC-720p( 155): get_parameter: OMX_IndexParamVideoProfileLevelQuerySupported for Input port returned Profile:1, Level:2048
E/OMX-VENC-720p( 155): Profile/Level set equal to 1/64
E/OMX-VENC-720p( 155): bool venc_dev::venc_validate_profile_level(OMX_U32*, OMX_U32*): Returning with eProfile = 1Level = 64
E/OMX-VENC-720p( 155):
E/OMX-VENC-720p( 155): venc_set_intra_period: nPFrames = 25 nBFrames = 0
E/OMX-VENC-720p( 155): bool venc_dev::venc_validate_profile_level(OMX_U32*, OMX_U32*): Returning with eProfile = 1Level = 64
E/OMX-VENC-720p( 155): Calling set level (Bitrate) with 15
E/OMX-VENC-720p( 155):
E/OMX-VENC-720p( 155): allocate_input_buffer()::
E/OMX-VENC-720p( 155):
E/OMX-VENC-720p( 155): allocate_input_buffer()::
E/OMX-VENC-720p( 155):
E/OMX-VENC-720p( 155): allocate_input_buffer()::
E/OMX-VENC-720p( 155):
E/OMX-VENC-720p( 155): allocate_output_buffer()::
E/OMX-VENC-720p( 155):
E/OMX-VENC-720p( 155): actual cnt = 5
E/OMX-VENC-720p( 155):
E/OMX-VENC-720p( 155): allocate_output_buffer()::
E/OMX-VENC-720p( 155):
E/OMX-VENC-720p( 155): actual cnt = 5
E/OMX-VENC-720p( 155):
E/OMX-VENC-720p( 155): allocate_output_buffer()::
E/OMX-VENC-720p( 155):
E/OMX-VENC-720p( 155): actual cnt = 5
E/OMX-VENC-720p( 155):
E/OMX-VENC-720p( 155): allocate_output_buffer()::
E/OMX-VENC-720p( 155):
E/OMX-VENC-720p( 155): actual cnt = 5
E/OMX-VENC-720p( 155):
E/OMX-VENC-720p( 155): allocate_output_buffer()::
E/OMX-VENC-720p( 155):
E/OMX-VENC-720p( 155): actual cnt = 5
E/OMX-VENC-720p( 155):
E/OMX-VENC-720p( 155): unsigned int venc_dev::venc_start()(): Check Profile/Level set in driver before start
E/OMX-VENC-720p( 155):
E/OMX-VENC-720p( 155): unsigned int venc_dev::venc_start()(): Driver Profile[3]/Level[15] successfully SET
E/OMX-VENC-720p( 155):
E/OMX-VENC-720p( 155): ENC_CONFIG: Codec: 2, Profile 3, level : 15
E/OMX-VENC-720p( 155):
E/OMX-VENC-720p( 155): ENC_CONFIG: Width: 480, Height:360, Fps: 25
E/OMX-VENC-720p( 155):
E/OMX-VENC-720p( 155): ENC_CONFIG: Bitrate: 512000, RC: 3, I-Period: 25
E/OMX-VENC-720p( 155):
E/OMX-VENC-720p( 155): ENC_CONFIG: qpI: 0, qpP: 80, qpb: 0
E/OMX-VENC-720p( 155):
E/OMX-VENC-720p( 155): ENC_CONFIG: VOP_Resolution: 4343391, Slice-Mode: 1, Slize_Size: 0
E/OMX-VENC-720p( 155):
E/OMX-VENC-720p( 155): ENC_CONFIG: EntropyMode: 1, CabacModel: 0
E/OMX-VENC-720p( 155):
E/OMX-VENC-720p( 155): ENC_CONFIG: DB-Mode: 2, alpha: 0, Beta: 0
E/OMX-VENC-720p( 155):
E/OMX-VENC-720p( 155): ENC_CONFIG: IntraMB/Frame: 18, HEC: 843271745
E/OMX-VENC-720p( 155): Width 480, Height 360, w_round 480, h_round 368, yuv_size 294912 alignment 8192 count 2
E/OMX-VENC-720p( 155):
E/OMX-VENC-720p( 155): Allocated virt:0x4432e000, FD: 145 of size 294912
E/OMX-VENC-720p( 155):
E/OMX-VENC-720p( 155): Allocated virt:0x4432e000, FD: 145 of size 294912 at index: 0
E/OMX-VENC-720p( 155):
E/OMX-VENC-720p( 155): Allocated virt:0x44895000, FD: 147 of size 294912
E/OMX-VENC-720p( 155):
E/OMX-VENC-720p( 155): Allocated virt:0x44895000, FD: 147 of size 294912 at index: 1
E/TestEnc-JNI( 4127): Writer NOT started! 80000000
Acabo de descubrir mi problema ( tonto ): estaba llamando a start()
en mVideoEncoder
(la instancia de OMXCodec
) antes de llamar a start()
en MPEG4Writer
, y esto daba el UNKNOWN_ERROR
.
Lo resolví llamando a start()
solo en la instancia de MPEG4Writer
.
Hay un error que creo que es importante:
omxEncMeta->setInt32(kKeyBitRate, frameRate); // should set bitrate, 24 is too small
además
omxEncMeta->setInt32(kKeySampleRate, frameRate); // i don''t think is of any use
Entonces: asegúrate de que tu fuente devuelve esto
virtual sp<MetaData> getFormat() {
sp<MetaData> meta = new MetaData;
meta->setInt32(kKeyWidth, mWidth);
meta->setInt32(kKeyHeight, mHeight);
meta->setInt32(kKeyColorFormat, mColorFormat);
meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_RAW);
return meta;
}
El MediaBuffer que devuelve desde la fuente debe tener el tamaño correcto: 480 * 360 * 4 (creo que ese es el caso).
Debe proporcionar la salida de adb logcat: adb.exe logcat OMXClient: V OMXCodec: V *: W