Android: How to integrate a decoder to multimedia framework
In Android SF framework, the codecs are registered through media_codecs.xml
. In standard android distribution, an example media_codecs.xml
can be found here. All audio-visual components are registered as OMX
components.
1. Codec Registration
To register your video decoder, you would have to add a new entry under <Decoders>
list. To ensure that your codec is always picked up, please ensure that your codec is listed as the first entry for the specific MIME
type. An example entry for a H.264 decoder could be as below.
<Decoders>
<MediaCodec name="OMX.ABC.XYZ.H264.DECODER" type="video/avc" >
<Quirk name="requires-allocate-on-input-ports" />
<Quirk name="requires-allocate-on-output-ports" />
</MediaCodec>
<MediaCodec name="OMX.google.h264.decoder" type="video/avc" />
Where,
a.OMX.ABC.XYZ.H264.Decoder
is the name of your component
b. video/avc
is the MIME
type of your component. In this example, it denotes a AVC / H.264 video decoder.
c.The next 2 statements denote the quirks
or special requirements of your components. In the given example, requires-allocate-on-input-ports
indicates to the Stagefright
framework that the component prefers to allocate the buffers on all it's input ports. Similarly, the other quirk
is informing that the component will also prefer to allocate on it's output ports. For a list of supported quirks
in the system, you could refer to the function OMXCodec::getComponentQuirks
in OMXCodec.cpp file. These quirks translate into flags which are then read by the framework to create and initialize the components.
In the example illustration, it is shown that your OMX
component is registered prior to the default Google implemented video decoder.
NOTE: If you trying this on an end device, you will have to ensure that this entry is reflected in the final media_codecs.xml
file.
2. OMX Core Registration
To create your component and ensure that the correct factory method is invoked, you may have to register your OMX
Core with the Stagefright
framework.
To register a new core, you will have to create a new library named libstagefrighthw.so
which will be located at /system/lib
in your end system. This library will have to expose a createOMXPlugin
symbol which will be looked by dlsym
.
The registration of the OMX
core is thus: OMXMaster
invokes addVendorPlugin
which internally invokes addPlugin("libstagefrighthw.so")
. In addPlugin
, the createOMXPlugin
will be looked up using which the other function pointers for makeComponentInstance
, destroyComponentInstance
etc are initialized.
Once the OMX
core is initialized, you are ready to run your own your component within the android framework. The reference for OMXMaster
can be found here.
With these changes, your video decoder is integrated into the android stagefright framework.
In android multimedia framework how we decide which decoder will play this video if we have multiple decoder of same MIME type
There has been a related question on this topic where majority of the steps were covered in this answer.
In the parseXML
function, the list is populated by going through the media_codecs.xml
file and the codecs are listed in the order in which they are listed i.e. first codec in the file will be the first one in the list to be tried, when we have multiple codecs for same MIME
type.
In case one wishes to ensure that their custom codec is employed, it should be enlisted as the first codec in the media_codecs.xml
for easier integration.
How to create a stagefright plugin
From your question, it appears that you are looking at a recommendation which is specific for Ice-Cream Sandwich
or earlier versions of Android. The first thing you should be clear about is the version of the android i.e. Ice-Cream Sandwich
or before or JellyBean
and after. The integration of codecs is different across different releases of Android.
I have already commented on your other question which is specific for JellyBean
and later (Reference: Android: How to integrate a decoder to multimedia framework)
If you would like to integrate your codec in Ice-Cream Sandwich
or before, the steps are already available in your question. In addition to adding the decoder into kDecoderInfo
list, you may like to setup certain quirks as shown here.
For the question on OMXCodec.cpp
, you can find this file at frameworks/base/media/libstagefright/
in case of Ice-Cream Sandwich
and frameworks/av/media/libstagefright/
in case of JellyBean
.
If you have followed all the steps to integrate the video decoder into the Stagefright
framework, then the easiest test would be to perform the following:
Copy a media file into SD-Card
In
OMXCodec.cpp
, enable logs by removing the comment in this statement//#define LOG_NDEBUG 0
and run amm
in the directory. Copy the rebuiltlibstagefright.so
to/system/lib
on your device.Enable
logcat
and start capturing logs.Goto gallery, select your file and allow the standard player to play your file.
Check your log file if the player has selected your
OMX
component by searching for your component name. If found, your integration of codec intoStagefright
is successful. Else, you will have to debug and find out what is the problem.
Postscript:
Based on your queries, I presume you aren't familiar with Android sources. Please refer to androidxref site to become familiar with
AOSP
distributions.Unless you are planning to support a new media file-format, you will not require to support
Extractor
class.MediaExtractor
abstracts a file-format parser and helps to de-multiplex the different tracks in a media file.
I hope with this information, you should be able to get your codec integrated and functional in Android.
Custom Wrapper Codec Integration into Android
In this post, I am using H.264
as an example, but the solution(s) can be extended to support other codecs like MPEG-4
, VC-1
, VP8
etc. There are 2 possible solutions to solve your problem, which I am enlisting below, each with their own pros and cons to help you take an informed decision.
Solution 1: Extend the codec to support new mode
In JellyBean
, one could register the same OMX
component with same MIME
types as 2 different component names viz., OMX.ABC.XYZ
and OMX.ABC.XYZ.secure
. The former is used for normal playback and is the more commonly used component. The latter is used when the parser i.e. MediaExtractor
indicates the presence of secure content. In OMXCodec::Create
, after findMatchingCodecs
returns a list of codecs, we can observe the choice to select .secure
component as here.
Steps to follow:
In your platform, register another component with some new extension like
OMX.H264.DECODER.decrypt
or something similar. Change is required only inmedia_codecs.xml
. The choice of whether to register a new factory method or have a common factory method is your choice.From your parser, when you encounter the specific use-case, set a new flag like
kKeyDecryptionRequired
. For this you will have to define a new flag inMetadata.h
and a corresponding quirk inOMXCodec.h
.Modify the
OMXCodec::create
method to append a.decrypt
suffix similar to the.secure
suffix as shown above.With all changes in
OMXCodec
,Metadata
,MediaExtractor
modules, you will have to rebuild onlylibstagefright.so
and replace the same on your platform.
Voila!! your integration should be complete. Now comes the main challenge inside the component. As part of the component implementation, you should be able to differentiate between an ordinary component creation and .decrypt
component creation.
From a runtime perspective, assuming that your component is aware of the fact that it is a .decrypt
component or not, you could handle the decryption
as part of the OMX_EmptyThisBuffer
call, where you could decrypt the data and then pass it to underlying codec.
Pros: Easy to integrate, Minimal changes in Android framework, Scalable to other codecs, No new MIME
type registration required.
Cons: You need to track the future revisions of android, specifically on the new quirks, flags and choice of .decrypt
extension. If Google decides to employ something similar, you will have to adapt / modify your solution accordingly.
Solution 2: Registration of new MIME Type
From your question, it is not clear if you were able to define the MIME
type or not and hence, I am capturing the steps for clarity.
Steps to follow:
Register a new
MIME
type atMediaDefs
as shown here. For example, you could employ a newMIME
type asconst char *MEDIA_MIMETYPE_VIDEO_AVC_ENCRYPT = "video/avc-encrypt";
Register your new component with this updated
MIME
type inmedia_codecs.xml
. Please note that you will have to ensure that the component quirks are also handled accordingly.In
OMXCodec::setVideoOutputFormat
method implementation, you will have to introduce the support for handling your newMIME
type as shown forH.264
here. Please note that you will have to handle similar changes inOMXCodec
to support the newMIME
type.In
MediaExtractor
, you will have to signal theMIME
type for thevideo
track using the newly defined type. With these changes, your component will be selected and created.
However, the challenge still remains: Where to perform the decryption? For this, you could as well employ the same solution as described in the previous section i.e. handle the same as part of OMX_EmptyThisBuffer
call.
Pros: None that I can think of..
Cons: First, solution is not scalable. You will have to keep adding newer MIME
types and keep modifying the Stagefright
framework. Next, the changes in OMXCodec
will require corresponding changes in MediaExtractor
. Hence, even though your initial focus is on MP4
extractor, if you wish to extend the solution to other container formats like AVI
, MKV
, you will have to include the support for new MIME
types in these extractors.
Lastly, some notes.
As a preferred solution, I would recommend Solution 1 as it is easy and simple.
I haven't touched upon
ACodec
based implementation of the codec. However, I do feel that Solution 1 would be a far more easier solution to implement even if such a support is required in future.If you aren't modifying the
OMX
core, you shouldn't require to modify thelibstagefrighthw.so
. Just FYI, this is typically implemented by the vendors as part of their vendor specific modules as invendor/<xyz>/hardware/...
. You need to check with your platform provider on the sources forlibstagefrighthw.so
.
Can i encode or decode video in Android using OpenCORE or StageFright?
You should use MediaCodec api and not any lower level api. The MediaCodec api will then use the appropriate framework internally. This is because android vendors will integrate their own codecs and hardware / dsp accelerated codecs into the framework and set those as default for MediaCodec api. They will ensure their codecs work with MediaCodec api. If you use MediaCodec api it will work on all devices irrespective of the framework being used below. That is what that api is for.
Unless you specifically want to do some testing with OpenCore/Stagefright don't go there.
Related Topics
Why Ondraw Is Not Called After Invalidate()
Android Ndk C++ Jni (No Implementation Found for Native...)
Cannot Resolve Method 'Getsupportfragmentmanager ( )' Inside Fragment
Use Recyclerview Inside Scrollview with Flexible Recycler Item Height
Admob Getting an Ad Response. Errorcode: 0 Failed to Load Ad:0
Why Getcontext() in Fragment Sometimes Returns Null
How to Use Bluetooth in Android Emulator
Running a Specific Instrumentation Unit Test with Gradle
Materialcomponents Theme Alert Dialog Buttons
How to Set Notification with Custom Sound in Android
Custom Layout That Rounds the Corners of Its Content
"No Resource Identifier Found for Attribute 'Showasaction' in Package 'Android'"
How to Setcontentview in a Fragment
Android Navigation Architecture Component - Get Current Visible Fragment