171 lines
4.7 KiB
C++
171 lines
4.7 KiB
C++
|
|
#include "HardDecode.h"
|
||
|
|
|
||
|
|
using namespace std;
|
||
|
|
|
||
|
|
HardDecode::HardDecode()
|
||
|
|
{
|
||
|
|
;
|
||
|
|
}
|
||
|
|
|
||
|
|
HardDecode::~HardDecode()
|
||
|
|
{
|
||
|
|
;
|
||
|
|
}
|
||
|
|
|
||
|
|
int HardDecode::hardDecoderInit(unsigned int uiWidth, unsigned int uiHeight, unsigned int uiFrameRate, AVCodecParameters *pCodecParameters)
|
||
|
|
{
|
||
|
|
uiWidth_ = uiWidth; uiHeight_ = uiHeight;
|
||
|
|
uiFrameRate_ = uiFrameRate;
|
||
|
|
this->pCodecParameters_ = pCodecParameters;
|
||
|
|
|
||
|
|
av_log_set_level(AV_LOG_ERROR);
|
||
|
|
|
||
|
|
// AVCodecID codec_id = AV_CODEC_ID_H264; //解码H264
|
||
|
|
// pCodec_ = avcodec_find_decoder(codec_id); //获取解码器
|
||
|
|
|
||
|
|
pCodec_ = avcodec_find_decoder(this->pCodecParameters_->codec_id);
|
||
|
|
|
||
|
|
if (pCodec_ == nullptr) {
|
||
|
|
LogError << "cannot find decoder !";
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
//创建上下文
|
||
|
|
pCodecCtx_ = avcodec_alloc_context3(pCodec_);
|
||
|
|
if (!pCodecCtx_){
|
||
|
|
LogError << "Could not allocate video codec context";
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
// 将AVCodecParameters结构体中码流参数拷贝到AVCodecContext结构体中,format, width, height, codec_type等
|
||
|
|
avcodec_parameters_to_context(pCodecCtx_, this->pCodecParameters_);
|
||
|
|
if (!pCodecCtx_) {
|
||
|
|
LogError << "Cannot alloc context.";
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
//打开解码器
|
||
|
|
int iRet = 1;
|
||
|
|
if ((iRet = avcodec_open2(pCodecCtx_, pCodec_, nullptr)) < 0) {
|
||
|
|
LogError << "cannot open decoder, Ret:" << iRet;
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
//分配packet
|
||
|
|
pPacket_ = av_packet_alloc();
|
||
|
|
if (!pPacket_){
|
||
|
|
LogError << "Could not allocate video packet";
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
// av_init_packet(pPacket_);
|
||
|
|
|
||
|
|
//分配frame
|
||
|
|
pSrcFrame_ = av_frame_alloc();
|
||
|
|
if (!pSrcFrame_) {
|
||
|
|
LogError << "Could not allocate video src pFrame";
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
pDstFrame_ = av_frame_alloc();
|
||
|
|
if (!pDstFrame_) {
|
||
|
|
LogError << "Could not allocate video dst pFrame";
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
// printf("after align down video_width: %d, video_height: %d\n", uiWidth_, uiHeight_);
|
||
|
|
|
||
|
|
int bufferSize = av_image_get_buffer_size(AV_PIX_FMT_YUV420P,
|
||
|
|
pCodecCtx_->width,
|
||
|
|
pCodecCtx_->height, 1);
|
||
|
|
outBuffer_ = (unsigned char *) av_malloc(bufferSize);
|
||
|
|
av_image_fill_arrays(pDstFrame_->data,
|
||
|
|
pDstFrame_->linesize,
|
||
|
|
outBuffer_,
|
||
|
|
AV_PIX_FMT_YUV420P,
|
||
|
|
pCodecCtx_->width,
|
||
|
|
pCodecCtx_->height, 1);
|
||
|
|
|
||
|
|
pSwsContext_ = sws_getContext(pCodecCtx_->width, pCodecCtx_->height, pCodecCtx_->pix_fmt,
|
||
|
|
pCodecCtx_->width, pCodecCtx_->height, AV_PIX_FMT_YUV420P, SWS_BICUBIC, nullptr, nullptr, nullptr);
|
||
|
|
return 1;
|
||
|
|
}
|
||
|
|
|
||
|
|
int HardDecode::hardDecoderDeInit()
|
||
|
|
{
|
||
|
|
if (pCodecParameters_){
|
||
|
|
av_free(pCodecParameters_);
|
||
|
|
pCodecParameters_ = nullptr;
|
||
|
|
}
|
||
|
|
if(outBuffer_){
|
||
|
|
av_free(outBuffer_);
|
||
|
|
outBuffer_ = nullptr;
|
||
|
|
}
|
||
|
|
if(pSrcFrame_){
|
||
|
|
av_frame_free(&pSrcFrame_);
|
||
|
|
pSrcFrame_ = nullptr;
|
||
|
|
}
|
||
|
|
if(pDstFrame_){
|
||
|
|
av_frame_free(&pDstFrame_);
|
||
|
|
pDstFrame_ = nullptr;
|
||
|
|
}
|
||
|
|
if(pPacket_){
|
||
|
|
av_packet_free(&pPacket_);
|
||
|
|
pPacket_ = nullptr;
|
||
|
|
}
|
||
|
|
if(pCodecParserCtx_){
|
||
|
|
av_parser_close(pCodecParserCtx_);
|
||
|
|
pCodecParserCtx_ = nullptr;
|
||
|
|
}
|
||
|
|
if(pCodecCtx_){
|
||
|
|
avcodec_close(pCodecCtx_);
|
||
|
|
av_free(pCodecCtx_);
|
||
|
|
pCodecCtx_ = nullptr;
|
||
|
|
}
|
||
|
|
if(pSwsContext_){
|
||
|
|
sws_freeContext(pSwsContext_);
|
||
|
|
pSwsContext_ = nullptr;
|
||
|
|
}
|
||
|
|
return 1;
|
||
|
|
}
|
||
|
|
|
||
|
|
int HardDecode::hardDecoder(void* pOutputData,unsigned int* puiOutputDataSize)
|
||
|
|
{
|
||
|
|
int ret;
|
||
|
|
|
||
|
|
ret = avcodec_send_packet(this->pCodecCtx_, this->pPacket_); //接收packet解码
|
||
|
|
if (ret < 0) {
|
||
|
|
LogError << "Error sending a packet for decoding " << ret;
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
while (ret >= 0) {
|
||
|
|
ret = avcodec_receive_frame(this->pCodecCtx_, this->pSrcFrame_); //解码
|
||
|
|
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF){
|
||
|
|
LogWarn << "During decoding eof";
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
else if (ret < 0) {
|
||
|
|
LogError << "Error during decoding";
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
sws_scale(this->pSwsContext_,
|
||
|
|
(const uint8_t *const *)this->pSrcFrame_->data,
|
||
|
|
this->pSrcFrame_->linesize,
|
||
|
|
0,
|
||
|
|
this->pCodecCtx_->height,
|
||
|
|
this->pDstFrame_->data,
|
||
|
|
this->pDstFrame_->linesize);
|
||
|
|
|
||
|
|
fflush(stdout);
|
||
|
|
|
||
|
|
int iSize = this->pCodecCtx_->width * this->pCodecCtx_->height;
|
||
|
|
|
||
|
|
memcpy(pOutputData, this->pDstFrame_->data[0], iSize); //Y
|
||
|
|
memcpy(pOutputData+iSize, this->pDstFrame_->data[1], iSize/4); //U
|
||
|
|
memcpy(pOutputData+iSize+iSize/4, this->pDstFrame_->data[2], iSize/4); //V
|
||
|
|
*puiOutputDataSize = iSize*3/2;
|
||
|
|
return iSize*3/2;
|
||
|
|
}
|
||
|
|
return 0;
|
||
|
|
}
|