在Ubuntu和Android中使用ffmpeg全格式解码视频文件(2)

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    
DIVXDIVX3~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 Sparkversion0,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    
RVRV8~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) { 

猜你喜欢

转载自blog.csdn.net/hp9016/article/details/88637777