/* * 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, };