int VideoDecodec::H265EnCodeThread(void *arg)
{
VideoDecodec *pVideoc = (VideoDecodec *)arg;
AVPacket pkt1 = { 0 };
AVPacket encodePkt = { 0 };
AVPacket* decodePacket = &pkt1;
AVPacket* encodePacket = &encodePkt;
AVFrame *pDecodeFrame = nullptr;
pDecodeFrame = av_frame_alloc();
std::ofstream fileHandle;
if (!fileHandle.is_open())
{
fileHandle.open("my.h265", std::ios::binary);
}
AVDictionary *options = 0;
//声明了编码速度,值有ultrafast、superfast、veryfast、faster、fast、medium、slow、slower、veryslow、placebo,越快视频质量则越差
av_dict_set(&options, "preset", "placebo", 0);
//实现实时编码(即编码速度不慢于输入速度)
av_dict_set(&options, "tune", "zerolatency", 0);
AVCodec *pEncoderAVCodec = avcodec_find_encoder(AV_CODEC_ID_H265);
AVCodecContext *pEncoderAVCodecContext = avcodec_alloc_context3(pEncoderAVCodec);
pEncoderAVCodecContext->codec_id = AV_CODEC_ID_H265;
pEncoderAVCodecContext->codec_type = AVMEDIA_TYPE_VIDEO;
pEncoderAVCodecContext->pix_fmt = AV_PIX_FMT_YUV420P;
pEncoderAVCodecContext->width = 720;
pEncoderAVCodecContext->height = 480;
pEncoderAVCodecContext->time_base.num = 1;
pEncoderAVCodecContext->time_base.den = 25; //时间基
pEncoderAVCodecContext->framerate = { 25,1 };//帧率
pEncoderAVCodecContext->bit_rate = 4096 * 1024;//重要,最终视频的码率
pEncoderAVCodecContext->gop_size = 25;//关键帧间隔
pEncoderAVCodecContext->qmin = 10;//最小压缩质量
pEncoderAVCodecContext->qmax = 20;//最大压缩质量,与最小质量一起控制压缩后的图像质量
pEncoderAVCodecContext->max_b_frames = 0;//不输出B帧,输出B帧后的时间戳控制较为繁琐
pEncoderAVCodecContext->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;//设置后通过extradata获取sps、pps
avcodec_open2(pEncoderAVCodecContext, pEncoderAVCodec, &options);
AVFrame *pDestFrame = NULL;
pDestFrame = av_frame_alloc();
pDestFrame->width = 720;
pDestFrame->height = 480;
pDestFrame->format = AV_PIX_FMT_YUVJ420P;
int nDestFrameSize = av_image_get_buffer_size(AV_PIX_FMT_YUVJ420P, pDestFrame->width, pDestFrame->height, 1);
uint8_t* pszDestBuffer = (uint8_t*)av_malloc(nDestFrameSize);
//将pszDestBuffer挂载在pDestFrame帧的图片缓存指针,需要手动删除
av_image_fill_arrays(pDestFrame->data, pDestFrame->linesize, pszDestBuffer, AV_PIX_FMT_YUVJ420P, pDestFrame->width, pDestFrame->height, 1);
while (!pVideoc->m_pDecodec->IsStop())
{
if (pVideoc->m_pDecodec->IsPause())
{
SDL_Delay(10);
continue;
}
if (pVideoc->videoq.GetPacketQueue(decodePacket, 1) < 0)
{
break;
}
if (decodePacket->data == pVideoc->m_pDecodec->m_FlushPkt.data)
{
avcodec_flush_buffers(pVideoc->m_pAVCodecContext);
continue;
}
if (avcodec_send_packet(pVideoc->m_pAVCodecContext, decodePacket) != 0) continue;
if (avcodec_receive_frame(pVideoc->m_pAVCodecContext, pDecodeFrame) != 0) continue;
pVideoc->ConvertWidthHeightOfFrame(pDecodeFrame, pDestFrame);
if (avcodec_send_frame(pEncoderAVCodecContext, pDestFrame) != 0) continue;
int nRet = 0;
while (true)
{
nRet = avcodec_receive_packet(pEncoderAVCodecContext, encodePacket);
if (nRet == AVERROR(EAGAIN) || nRet == AVERROR_EOF)
{
break;
}
else
{
if (fileHandle)
{
for (int i = 0; i < (encodePacket->size - 4); i++)
{
if ((encodePacket->data[i] == 0x00) && (encodePacket->data[i + 1] == 0x00) && (encodePacket->data[i + 2] == 0x00) && (encodePacket->data[i + 3] == 0x01))
{
//IDR帧前面添加视频参数
if (((encodePacket->data[i + 4] & 0x7E) >> 1) == 19)
{
fileHandle.write((char*)(pEncoderAVCodecContext->extradata), pEncoderAVCodecContext->extradata_size);
}
fileHandle.write((char*)(&(encodePacket->data[i])), encodePacket->size - i);
break;
}
}
av_packet_unref(encodePacket);
av_packet_unref(decodePacket);
}
}
}
}
fileHandle.close();
while (1)
{
avcodec_send_packet(pVideoc->m_pAVCodecContext, NULL);
if (avcodec_receive_frame(pVideoc->m_pAVCodecContext, pDecodeFrame) != 0)
{
break;
}
av_packet_unref(decodePacket);
}
av_free(pDecodeFrame);
av_free(pDestFrame->data[0]);
//
pVideoc->video_tid = 0;
//release buffer
SDL_Event event;
event.type = FF_QUIT_EVENT;
event.user.data1 = pVideoc->m_pDecodec;
SDL_PushEvent(&event);
return 0;
}