Android: MPEG4Writer fails to start when using OMXCodec as MediaSource

2.1k views Asked by At

I'm trying to encode a video from a byte array buffer and to do so I'm using MPEG4Writer API from native code.

I have created my custom MediaSource class to provide the data and I'm wrapping it with OMXCodec to give it to MPEG4Writer:

sp<MediaSource> mVideoEncoder = OMXCodec::Create(client.interface(), omxEncMeta, true, mVideoOutSource);
mVideoEncoder->start();

mVideoOutSource is my custom MediaSource class, omxEncMeta is the following:

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);

but when I call start() method it returns the error code UNKNOWN_ERROR.

Instead, if I try to give to MPEG4Writer directly my custom MediaSource (without wrapping it with OMXCodec it starts successfully but eventually it will stop recording with the error Missing codec specific data (after about 12 frames), and I think this is because my custom MediaSource provides only informations about the actual frames but nothing about the codec format.

I'm sure I'm missing something with OMXCodec, but I can't figure out what... Is there anyone who could provide me with a working example of a custom MediaSource for encoding? Or give me some hints on why this is not working at all?
If you need more informations just ask, thanks!

EDIT: I'm developing this against API 14 so please don't suggest me to use MediaCodec from API 16 :)

EDIT: This is how I'm starting 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!");
}

This is the output of 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
2

There are 2 answers

0
dmarcato On BEST ANSWER

I just figured out my (dumb) issue: I was calling start() on mVideoEncoder (the OMXCodec instance) before calling start() on MPEG4Writer, and this was giving the UNKNOWN_ERROR.

I solved by calling start() only on MPEG4Writer instance.

3
Dragos Iordache On

There is an error that I think is important:

omxEncMeta->setInt32(kKeyBitRate, frameRate); // should set bitrate, 24 is too small

also

omxEncMeta->setInt32(kKeySampleRate, frameRate); // i don't think is of any use

Then: make sure your source returns this

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;
}

The MediaBuffer you return from source should be the right size: 480*360*4(i think that is the case).

You should provide the adb logcat output: adb.exe logcat OMXClient:V OMXCodec:V *:W