基于S3C6410和ffmpeg的视频加速示例

/*
* Video Acceleration (shared data between FFmpeg and the video player)
* HW decode acceleration for MPEG-4, H.264, H263 and VC-1
* Using Samsung Multi-Format Codec API
*
* Copyright(C) 2012  TuYuanDong
* author:	tuyaundong
* email:	[email protected]
* Date:		2012-02-27
*
*/
#include "s3c_va.h"
#include "./libavcodec/avcodec.h"
#include "./libavcodec/mpeg4video.h"
#include "./libavcodec/h264.h"
#include "SsbSipH264Decode.h"
#include "SsbSipLogMsg.h"
#include "vaapi.h"

#define NAL_UNIT_TYPE_TYPE(n)    ((0x001F) & (n))
static const uint8_t delimiter_h264[4]  = {0x00, 0x00, 0x00, 0x01};

/** Initialize and start decoding a frame with S3CMFC API. */
static int start_frame(AVCodecContext          *avctx,
					   av_unused const uint8_t *buffer,
					   av_unused uint32_t       size)
{
	int is_avc = 0;
	SSBSIP_H264_STREAM_INFO stream_info;

	//如果decode_slice函数解码失败,则需停止硬解,转向软解
	if(bDecSuc == -1)
	{
		avctx->hwaccel = NULL; 
		LOG_MSG(LOG_TRACE,__FUNCTION__,"Hardware decode video failed,being used soft decoder\r\n");
		return -1;
	}
	
	if(ResetVideoAccelerator(avctx,SsbSipH264DecodeDeInit) < 0)
		goto fail;

	if(avctx->extradata_size > 0)
	{
		uint8_t * p = avctx->extradata;
		if(p[0] == 0x01)
			is_avc = 1;
	}

	if(bFistFrame && size >0)  //初始化硬解加速器
	{
		//	1. Create new instance
		handle = SsbSipH264DecodeInit();
		if (handle == NULL) {
			LOG_MSG(LOG_ERROR, __FUNCTION__, "Decoder Init Failed\n");
			goto fail;
		}
	
		//	2. Obtaining the Input Buffer
		pStrmBuf = SsbSipH264DecodeGetInBuf(handle,BUFFER_SIZE);
		if (pStrmBuf == NULL) {
			LOG_MSG(LOG_ERROR, __FUNCTION__, "SsbSipH264DecodeGetInBuf Failed.\n");			
			goto fail;
		}
	}
		
	BufSize = 0;
	if(is_avc)
	{
		uint8_t* buf = buffer;
		int tot_size = 0;
		if(bFistFrame && avctx->extradata_size > 0)
		{
			uint8_t* p  = avctx->extradata;	
			int i, cnt, nalsize;
			
			// Decode sps from avcC
		        cnt = *(p+5) & 0x1f; // Number of sps
		        p += 6;
		        for (i = 0; i < cnt; i++) {
		            	nalsize = AV_RB16(p);
		            	if((nalsize+2) > avctx->extradata_size - (p-avctx->extradata))
		               	return -1;
		            	//copy h264 data
		           	memcpy(pStrmBuf+BufSize,delimiter_h264,sizeof(delimiter_h264));
				BufSize += sizeof(delimiter_h264);
				p += 2;
				memcpy(pStrmBuf+BufSize,p,nalsize);			            	
			  	BufSize += nalsize;

				p += nalsize;				
		        }
			
		        // Decode pps from avcC
		        cnt = *(p++); // Number of pps
		        for (i = 0; i < cnt; i++) {
		            nalsize = AV_RB16(p);
		            if((nalsize+2) > avctx->extradata_size  - (p-avctx->extradata))
		                return -1;
				//copy h264 data
		           	memcpy(pStrmBuf+BufSize,delimiter_h264,sizeof(delimiter_h264));
				BufSize += sizeof(delimiter_h264);	
				p += 2;
				memcpy(pStrmBuf+BufSize,p,nalsize);			              
				BufSize += nalsize;

				p += nalsize;
		        }
			//fwrite(avctx->extradata, 1, avctx->extradata_size, fp1);
		}
		unsigned char      nal_type = 255;
		int num_iframe = 0;
		do
		{
			int slice_size = buf[0]<<24 | buf[1]<<16 | buf[2]<<8 | buf[3];			
			nal_type = NAL_UNIT_TYPE_TYPE(buf[4]);
			//printf("slice size=%d nal_type=%d\n",slice_size,nal_type);	
			if(nal_type == 5)
				num_iframe ++;

			memcpy(pStrmBuf+BufSize,delimiter_h264,sizeof(delimiter_h264));
			BufSize += sizeof(delimiter_h264);				
			memcpy(pStrmBuf+BufSize,buf+4,slice_size);
			BufSize += slice_size;
			
			buf += slice_size+4;
			tot_size += slice_size+4;	

		}while(tot_size < size);

		if(num_iframe > 1)
			goto fail;
	}
	else
	{
		if (bFistFrame && avctx->extradata_size != 0)
		{
			memcpy(pStrmBuf+BufSize,avctx->extradata,avctx->extradata_size);
			BufSize += avctx->extradata_size;
		}
		
		memcpy(pStrmBuf+BufSize,buffer,size);
		BufSize += size;
	}

	if(bFistFrame)
	{
		//	3. Configuring the instance with the config stream SsbSipXXXDecodeExe
		int ret =SsbSipH264DecodeExe(handle, BufSize);
		if (ret != SSBSIP_H264_DEC_RET_OK) {
			LOG_MSG(LOG_ERROR, __FUNCTION__, "Decoder SsbSipH264DecodeExe Failed err=%d.\n",ret);
			goto fail;
		}	
	
		///   4. Get stream information 
		SsbSipH264DecodeGetConfig(handle, H264_DEC_GETCONF_STREAMINFO, &(stream_info));
		LOG_MSG(LOG_TRACE, __FUNCTION__,"STREAMINFO width=%d   height=%d\r\n",stream_info.width, stream_info.height);
		bFistFrame = 0;
	}
		
	BufSize = size;
	return 0;
	
fail:
	LOG_MSG(LOG_TRACE,__FUNCTION__,"Hardware decode video failed,being used soft decoder\r\n");
	if(handle)
	{
		SsbSipH264DecodeDeInit(handle);
		handle = NULL;
	}
	avctx->hwaccel = NULL;  //用于跳转到软解方案中
	return -1;
}

/** End a hardware decoding based frame. */
static int end_frame(AVCodecContext *avctx)
{
	struct H264Context *h = avctx->priv_data;
    	struct MpegEncContext *s = &h->s;
		
	Picture* pic = s->current_picture_ptr;		
	uint8_t* pYUVBuf = NULL;
	long size;
	
	if(bDecSuc > 0 && handle)
	{
		pYUVBuf = SsbSipH264DecodeGetOutBuf(handle,&size);
		if(pYUVBuf)
		{
			avpicture_fill(pic,pYUVBuf,pic->format,pic->width,pic->height);
			//pYUVBuf 中的YUV420在内存中不是连续的
			pic->data[1] = (int8_t*)(pYUVBuf+4*size/6);
			pic->data[2] = (int8_t*)(pYUVBuf+5*size/6);
		}
//				LOG_MSG(LOG_ERROR, __FUNCTION__,"width=%d height=%d size[%d] data[%p][%p][%p] data2[%p][%p][%p]\r\n",
//							pic->width,pic->height,size,
//							pic->data[0],pic->data[1],pic->data[2],pYUVBuf,pYUVBuf+4*size/6,pYUVBuf+5*size/6);
	}
	return 0;
}

/** Decode the given h264 slice with S3CMFC API. */
static int decode_slice(AVCodecContext *avctx,
						const uint8_t  *buffer,
						uint32_t        size)
{
	int ret = 0;

	bDecSuc = 0; 
	ret =SsbSipH264DecodeExe(handle, BufSize);
	if (ret != SSBSIP_H264_DEC_RET_OK) {
		bDecSuc = -1;
		return -1;
	}
	else	
		bDecSuc = 1;
	
	return 0;
}


AVHWAccel ff_h264_s3c_hwaccel = {
	"h264_s3c",
	AVMEDIA_TYPE_VIDEO,
	CODEC_ID_H264,
	PIX_FMT_YUV420P,
	0,
	NULL,
	start_frame,	
	decode_slice,
	end_frame,
	0,
};

你可能感兴趣的:(基于S3C6410和ffmpeg的视频加速示例)