问题描述
所以我尝试使用 ffmpeg c++ 来编码 rgb h264 视频,我看到两个选项:
-
使用 sws_scale 将 rgb 帧数据转换为 yuv420 并正常编码(这可行,但似乎存在某种内存泄漏并在大约 20 秒后冻结)
使用 libx264rgb 直接对 rgb 数据进行编码(最好是因为我知道将 rgb 转换为 yuv 时没有损失和颜色偏移,但是当我尝试使用这种方法时,输出的视频是全黑的)>
这是在 android 上,所以我使用的是 ffmpeg 移动工具包 (https://github.com/tanersener/ffmpeg-kit) full-gpl build,我认为它包括 libx264rgb,当我尝试通过首先按名称找到它来打开编解码器时,它会成功打开,是否存在使用 264rgb 编码时,还有什么需要做的不同吗?
这是我当前的代码:
#include "include/video_recorder.hpp"
void VideoCapture::Encode(AVCodecContext *enc_ctx,AVFrame *frame,AVPacket *pkt,FILE *outfile,int framesToWrite = 1) {
int ret;
/* send the frame to the encoder */
// if (frame)
// {
// log("Send frame %i at time %li",frameCounter,frame->pts);
// }
ret = avcodec_send_frame(enc_ctx,frame);
if (ret < 0)
{
log("Error sending a frame for encoding\n");
return;
}
while (ret >= 0)
{
ret = avcodec_receive_packet(enc_ctx,pkt);
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
{
return;
}
else if (ret < 0)
{
log("Error during encoding\n");
return;
}
// log("Write packet %li (size=%i)\n",pkt->pts,pkt->size);
for (int i = 0; i < framesToWrite; i++)
{
fwrite(pkt->data,1,pkt->size,outfile);
}
av_packet_unref(pkt);
}
}
void VideoCapture::AddFrame(rgb24 *data) {
if(!initialized) return;
if(startTime == 0) {
startTime = UnityEngine::Time::get_time();
log("Video global time start is %f",startTime);
}
int framesToWrite = 1;
// if (stabilizefPS) {
// framesToWrite = std::max(0,int(TotalLength() / (1.0f / float(fps * 2))) - frameCounter);
// log("Frames to write: %i,equation is int(%f / (1 / %i)) - %i",framesToWrite,TotalLength(),fps,frameCounter);
// }
if(framesToWrite == 0) return;
frameCounter += framesToWrite;
int ret;
/* make sure the frame data is writable */
ret = av_frame_make_writable(frame);
if (ret < 0)
{
log("Could not make the frame writable: %s",av_err2str(ret));
return;
}
// if (!swsCtx)
// {
// swsCtx = sws_getContext(c->width,c->height,AV_PIX_FMT_RGB24,c->width,AV_PIX_FMT_YUV420P,SWS_POINT,0);
// }
// int inLinesize[1] = {3 * c->width};
// sws_scale(swsCtx,(const uint8_t *const *)&data,inLinesize,frame->data,frame->linesize);
frame->pts = frameCounter;
/* encode the image */
Encode(c,frame,pkt,f,framesToWrite);
}
void VideoCapture::Finish()
{
//DELAYED FRAMES
// Encode(c,NULL,f);
fclose(f);
avcodec_free_context(&c);
av_frame_free(&frame);
av_packet_free(&pkt);
initialized = false;
}
void VideoCapture::Init(int videoWidth,int videoHeight,int fpsrate,int videoBitrate,bool stabilizefPS,std::string encodeSpeed,std::string filepath)
{
log("Setting up video at path " + filepath);
fps = fpsrate;
width = videoWidth;
height = videoHeight;
bitrate = videoBitrate * 1000;
filename = filepath.c_str();
this->stabilizefPS = stabilizefPS;
frameCounter = 0;
int ret;
codec = avcodec_find_encoder_by_name("libx264rgb");
if (!codec)
{
log("Codec not found");
return;
}
c = avcodec_alloc_context3(codec);
if (!c)
{
log("Could not allocate video codec context\n");
return;
}
pkt = av_packet_alloc();
if (!pkt)
return;
c->bit_rate = bitrate * 1000;
c->width = width;
c->height = height;
c->time_base = (AVRational){1,fps};
c->framerate = (AVRational){fps,1};
c->gop_size = 10;
c->max_b_frames = 1;
c->pix_fmt = AV_PIX_FMT_RGB24;
if (codec->id == AV_CODEC_ID_H264)
av_opt_set(c->priv_data,"preset",encodeSpeed.c_str(),0);
ret = avcodec_open2(c,codec,NULL);
if (ret < 0)
{
log("Could not open codec: %s\n",av_err2str(ret));
return;
}
log("Successfully opened codec");
f = fopen(filename,"wb");
if (!f)
{
log("Could not open %s\n",filename);
return;
}
frame = av_frame_alloc();
if (!frame)
{
log("Could not allocate video frame\n");
return;
}
frame->format = c->pix_fmt;
frame->width = c->width;
frame->height = c->height;
ret = av_frame_get_buffer(frame,0);
if (ret < 0)
{
log("Could not allocate the video frame data\n");
return;
}
initialized = true;
log("Finished initializing video at path %s",filename);
encodingThread = std::thread(&VideoCapture::encodeFrames,this);
}
void VideoCapture::encodeFrames()
{
log("Starting encoding thread");
while (initialized || !framebuffers.empty())
{
if (!framebuffers.empty())
{
std::unique_lock lock(framebuffer_mutex);
std::list<void*> listcopy(framebuffers); // copy the list
framebuffers.clear();
lock.unlock();
// Unlock and use the copy
// Now we use the copied list and it should be ours only
while (!listcopy.empty()) {
// log("size is %i",framebuffers.size());
auto it = listcopy.begin();
auto frameData = (rgb24 *) *it;
this->AddFrame(frameData);
// free(*it);
free(frameData);
listcopy.pop_front();
}
}
}
log("Ending encoding thread");
}
void VideoCapture::queueFrame(void *frame) {
std::unique_lock lock(framebuffer_mutex);
framebuffers.push_back(frame);
}
VideoCapture::~VideoCapture()
{
initialized = false; // should we force it to stop or force it to wait?
if (encodingThread.joinable())
encodingThread.join();
}```
解决方法
暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!
如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。
小编邮箱:dio#foxmail.com (将#修改为@)