1、如何在ffmpeg中加入对on2 api的调用
1.1 、ON2 Decoder在ffmpeg的修改位置及与CODEC_ID的对应关系
表2
ON2 Decoder | ffmpeg file | CODEC_ID | DIFF | Mark |
H264 | h264.c | CODEC_ID_H264 | ||
DIVX(DIVX3~6) | h263dec.c | CODEC_ID_MPEG4 | DIVX | |
DI50 | ||||
CODEC_ID_MSMPEG4V3 | DIVX3 | |||
MPEG4 | h263dec.c | CODEC_ID_MPEG4 | MP4V | |
H263 | h263dec.c | CODEC_ID_H263 | ||
Sorenson Spark(version0,1) | h263dec.c | CODEC_ID_FLV1 | FLV1 | |
MPEG2 | mpeg12.c | CODEC_ID_MPEG2VIDEO | ||
MPEG1 | mpeg12.c | CODEC_ID_MPEG1VIDEO | ||
VC-1 | vc1dec.c | CODEC_ID_VC1 | ||
CODEC_ID_WMV3 | ||||
RV(RV8~10) | rv34.c | CODEC_ID_RV30 | RV8 | |
CODEC_ID_RV40 | RV9&10 | |||
VP6 | vp6.c | CODEC_ID_VP6 | ||
CODEC_ID_VP6F | ||||
CODEC_ID_VP6A |
1.2 如何从ffmpeg的AVFrame中组装on2各种视频格式需要的frame/slice
1.2.1 H264
有两种方式为on2 decoder提供正确的raw data.
1.2.1.1 把每一个Nal数据分别传给on2
ffmpeg在提取nal数据的时候,会由变量is_avc做不同的判断来获得nal的长度
if (extradata && *extradata == 1)
is_avc = 1;
else
is_avc = 0;
if (is_avc)
search start code prefix:[0][0][1]
else
读AVPacket.data的第一个字节作为nal_size,以此循环
1.2.1.2 把每一个AVPacket的data转化为符合标准的一帧后传给on2
这个具体可以参见h264_mp4toannexb_bsf.c的h264_mp4toannexb_filter函数
1.2.2 MPEG1&2
AVPacket.data的数据不需要额外的处理即可被on2的解码。
1.2.3 MPEG4
1.2.3.1 MPEG4
对于mpeg4文件,header信息存放在extradata里面,所以在解码AVPacket的data前,我们应该先把extradata传给on2解码以获得该mpeg4流的头信息。因为ffmpeg在init的时候就要调用一次decode_frame,但此时on2不需要解码任何一帧,所以on2解码extradata的时期如下表:
表3
需要解extradata | 需要解数据帧 | |
初始化的时候 | YES | NO |
解第一帧的时候 | YES | YES |
解其他帧的时候 | NO | YES |
1.2.3.2 DIVX3
1.2.3.2.1 Divx3不属于mpeg4标准
1.2.3.2.2 Divx3没有startcode
1.2.3.2.3 解码前需要调用on2的api MP4DecSetinfo来设置视频流的宽高
1.2.3.2.4 解码Divx3时,没有DEC_HDRS_RDY这种状态,只有PIC_Decoded.
1.2.3.3 DIVX4~6
1.2.3.3.1 Divx4~6没有extradata
1.2.3.3.2 Divx4~6的CodecID与MPEG4一样,所以需要FourCC来区分
1.2.3.4 H263&Sorenson Spark
1.2.3.4.1 Sorenson Spark被认为H263(Sorenson Spark)
1.2.3.4.2 H263没有extradata
1.2.4 RV
1.2.4.1 RV各种版本说法的对应关系
表4
Video 版本 | Player 版本 | wiki Codecs | 视频编码标准 | FourCC |
Real Video | Real Player | RealVideo | H.263 | rv10 / rv 13 |
Real Video 2 | Real Player 6 / Real Player G2 | RealVideo G2 | H.263 | rv20 |
Real Video 3 | Real Player 8 | RealVideo 3 | Eearly Version of H.264 | rv30 |
Real Video 4 | Real Player 9~10 | RealVideo 4 | H.264 | rv40 |
1.2.4.2 RV数据组成结构
一帧rv数据,前20个字节,存储的是整帧的信息,其中前4个存储的是帧的长度,最后4个存储的是该帧slice的个数,比如n个。随后紧接着的n*8个字节存储的便是每个slice的头信息,每8个字节的前四个是标识该帧的合法性,后四个是该slice在整个frame的偏移量,如下图:
图5
1.2.4.3 MPlayer与Ffmpeg解析rm有所不同,并且在传给on2时帧数据需要处理
1.2.4.3.1 mplayer与ffmpeg在解析rm文件用的不是一套代码
1.2.4.3.2 mplayer与ffmpeg读出的rv数据不完全一致
1.2.4.3.3 mplayer送给decoder的数据,头信息比ffmpeg少一个slice的信息。
1.2.4.3.4 mplayer送给decoder的数据,尾部比ffmpeg多一部分信息。
1.2.4.3.5 mplayer能解析rv,需要把最后16个字节的数据删除
1.2.4.3.6 ffmpeg能解析rv8,必须把第一帧的最后一个slice去掉,包括slice的偏移和合法性。
1.2.4.3.7 ffmpeg中slice_count都是从AVPacket的data读的,不是从avctx获得的
1.2.4.3.8 ffmpeg一帧的数据(并不是所有帧)比On2 test解码出的数据多一个slice,包括头信息与data
1.2.4.3.9 ffmpeg已经解过frame info,并把它去掉,然后才发给decoder,我们需要利用ffmpeg已经获得的信息把slice infos传送给On2
1.2.5 VP6
从ffmpeg获得CodecID,如果是CODEC_ID_VP6A,则去掉AVPacket.data前三个字符后,On2才能解码。
1.2.6 VC1
1.2.6.1 对于profile为advanced的VC1视频,on2需要解码extradata
1.2.6.2 对于profile为advanced的VC1视频,每一帧的头部必须加上0x00,0x00,0x01,0x0d。
1.2.6.3 不能直接把ffmpeg中的profile传给on2,因为ffmpeg与on2的profile枚举值不同。
1.2.6.4 对于profile为simple&main的VC1视频,on2不能解码extradata,on2需要的metadata需要从avctx中获得。
1.2.6.5 simpler&main的文件,目前不能完全支持。
2、如何在Android中加入对on2 api的调用
2.1 CodecID与OMX_CODEC等的映射关系
表5
CODEC_ID | MIMETYPE | OMX_CODEC | ON2 DEC |
CODEC_ID_H264 | MEDIA_MIMETYPE_VIDEO_AVC | OMX_VIDEO_CodingAVC | H264 |
CODEC_ID_H263 | MEDIA_MIMETYPE_VIDEO_H263 | OMX_VIDEO_CodingH263 | MPEG4 |
CODEC_ID_FLV1 | MEDIA_MIMETYPE_VIDEO_FLV1 | OMX_VIDEO_CodingMPEG4 | |
CODEC_ID_MPEG4 | MEDIA_MIMETYPE_VIDEO_MPEG4 | ||
CODEC_ID_MSMPEG4V3 | |||
CODEC_ID_MPEG1VIDEO | MEDIA_MIMETYPE_VIDEO_MPEG1 | OMX_VIDEO_CodingMPEG2 | MPEG2 |
CODEC_ID_MPEG2VIDEO | MEDIA_MIMETYPE_VIDEO_MPEG2 | ||
CODEC_ID_VC1 | MEDIA_MIMETYPE_VIDEO_VC1 | OMX_VIDEO_CodingWMV | VC1 |
CODEC_ID_WMV3 | |||
CODEC_ID_RV30 | MEDIA_MIMETYPE_VIDEO_RV30 | OMX_VIDEO_CodingRV | RV |
CODEC_ID_RV40 | MEDIA_MIMETYPE_VIDEO_RV40 | ||
CODEC_ID_VP6 | MEDIA_MIMETYPE_VIDEO_VP6 | OMX_VIDEO_CodingVP6 | VP6 |
CODEC_ID_VP6F | MEDIA_MIMETYPE_VIDEO_VP6F | ||
CODEC_ID_VP6A | MEDIA_MIMETYPE_VIDEO_VP6A |
2.2 新增一个OMX_CODEC步骤,以OMX_VIDEO_CodingRV为例
2.2.1 注册Decoder名称
omx/system/src/openmax_il/omx_core/src/OMX_Core.c
{"OMX.NU.Video.Decoder", "video_decoder.rv"},
2.2.2 增加Decoder参数
omx/system/src/openmax_il/omx_core/inc/OMX_Video.h
typedef struct OMX_VIDEO_PARAM_RVTYPE {…}
typedef enum VIDDEC_DEFAULT_INPUT_INDEX
VIDDEC_DEFAULT_INPUT_INDEX_RV,
typedef enum VIDDEC_INIT_VALUE
VIDDEC_INIT_RV,
typedef struct VIDDEC_COMPONENT_PRIVATE
OMX_VIDEO_PARAM_RVTYPE* pRV;
#define VIDDEC_COMPONENTROLES_RV
#define VIDDEC_DEFAULT_RV_PORTINDEX
#define VIDDEC_DEFAULT_RV_VERSION
2.2.3 增加对Decoder的初始化
omx/video/src/openmax_il/video_decode/src/OMX_VideoDecoder.c
OMX_ERRORTYPE OMX_ComponentInit (OMX_HANDLETYPE hComponent)
OMX_MALLOC_STRUCT(pComponentPrivate->pRV, OMX_VIDEO_PARAM_RVTYPE,...);
2.2.4 增加Decoder参数的初始化
omx/video/src/openmax_il/video_decode/src/OMX_VideoDec_Utils.c
OMX_ERRORTYPE VIDDEC_Load_Defaults
case VIDDEC_INIT_RV:
2.2.5 增加Decoder参数的设置
omx/video/src/openmax_il/video_decode/src/OMX_VideoDecoder.c
static OMX_ERRORTYPE VIDDEC_GetParameter (OMX_IN OMX_HANDLETYPE hComponent,
case OMX_IndexParamVideoPortFormat:
case VIDDEC_DEFAULT_INPUT_INDEX_RV:
static OMX_ERRORTYPE VIDDEC_SetParameter (OMX_HANDLETYPE hComp,
case OMX_IndexParamVideoPortFormat:
case OMX_VIDEO_CodingRV:
2.2.6 增加Decoder解码所需资源的分配
omx/video/src/openmax_il/video_decode/src/OMX_VideoDecoder.c
static OMX_ERRORTYPE VIDDEC_Allocate_DSPResources
if (nPortIndex == pComponentPrivate->pInPortFormat->nPortIndex) {
else if (pPortDefIn->format.video.eCompressionFormat == OMX_VIDEO_CodingRV) {
else if (nPortIndex == pComponentPrivate->pOutPortFormat->nPortIndex) {
else if (pPortDefIn->format.video.eCompressionFormat == OMX_VIDEO_CodingRV) {
2.2.7 增加Decoder对Command的处理
omx/video/src/openmax_il/video_decode/src/OMX_VideoDec_Utils.c
OMX_ERRORTYPE VIDDEC_HandleCommand
if (pComponentPrivate->pInPortDef->format.video.eCompressionFormat == OMX_VIDEO_CodingRV) {
2.2.8 增加Decoder对资源的释放
omx/video/src/openmax_il/video_decode/src/OMX_VideoDecoder.c
static OMX_ERRORTYPE VIDDEC_FreeBuffer
else if (pPortDefIn->format.video.eCompressionFormat == OMX_VIDEO_CodingRV) {