gpt4 book ai didi

c++ - 如何编写 Live555 FramedSource 以允许我直播 H.264

转载 作者:可可西里 更新时间:2023-11-01 16:31:15 28 4
gpt4 key购买 nike

我一直在尝试编写一个派生自 Live555 中的 FramedSource 的类,它允许我将实时数据从我的 D3D9 应用程序流式传输到 MP4 或类似应用程序。

我在每一帧所做的是将后缓冲区作为纹理抓取到系统内存中,然后将其从 RGB -> YUV420P 转换,然后使用 x264 对其进行编码,然后理想情况下将 NAL 数据包传递到 Live555。我创建了一个名为 H264FramedSource 的类,它基本上是通过复制 DeviceSource 文件从 FramedSource 派生的。我没有将输入作为输入文件,而是将其作为 NAL 数据包更新每一帧。

我对编解码器和流媒体很陌生,所以我做的每件事都可能完全错误。在每个 doGetNextFrame() 中,我应该抓取 NAL 数据包并做类似的事情

memcpy(fTo, nal->p_payload, nal->i_payload)

我假设有效负载是我的帧数据(以字节为单位)?如果有人有一个他们从 FramedSource 派生的类的示例,它可能至少接近我正在尝试做的事情,我很乐意看到它,这对我来说是全新的,并且要弄清楚发生了什么有点棘手。 Live555 的文档几乎就是代码本身,这并不能让我很容易理解。

最佳答案

好吧,我终于有时间花在这上面并开始工作了!我敢肯定还有其他人会乞求知道如何去做,所以就在这里。

您将需要自己的 FramedSource 来获取每一帧、进行编码并为流式传输做好准备,我将很快为此提供一些源代码。

本质上是将 FramedSource 放入 H264VideoStreamDiscreteFramer,然后将其放入 H264RTPSink。像这样

scheduler = BasicTaskScheduler::createNew();
env = BasicUsageEnvironment::createNew(*scheduler);

framedSource = H264FramedSource::createNew(*env, 0,0);

h264VideoStreamDiscreteFramer
= H264VideoStreamDiscreteFramer::createNew(*env, framedSource);

// initialise the RTP Sink stuff here, look at
// testH264VideoStreamer.cpp to find out how

videoSink->startPlaying(*h264VideoStreamDiscreteFramer, NULL, videoSink);

env->taskScheduler().doEventLoop();

现在在您的主渲染循环中,将您已保存到系统内存的后备缓冲区转移到您的 FramedSource 以便对其进行编码等。有关如何设置编码内容的更多信息,请查看此答案 How does one encode a series of images into H264 using the x264 C API?

我的实现处于非常糟糕的状态,根本没有得到优化,由于编码原因,我的 d3d 应用程序运行在大约 15fps,哎呀,所以我将不得不研究这个。但就所有意图和目的而言,这个 StackOverflow 问题已得到解答,因为我主要是想知道如何流式传输它。我希望这对其他人有帮助。

至于我的 FramedSource,它看起来有点像这样

concurrent_queue<x264_nal_t> m_queue;
SwsContext* convertCtx;
x264_param_t param;
x264_t* encoder;
x264_picture_t pic_in, pic_out;


EventTriggerId H264FramedSource::eventTriggerId = 0;
unsigned H264FramedSource::FrameSize = 0;
unsigned H264FramedSource::referenceCount = 0;

int W = 720;
int H = 960;

H264FramedSource* H264FramedSource::createNew(UsageEnvironment& env,
unsigned preferredFrameSize,
unsigned playTimePerFrame)
{
return new H264FramedSource(env, preferredFrameSize, playTimePerFrame);
}

H264FramedSource::H264FramedSource(UsageEnvironment& env,
unsigned preferredFrameSize,
unsigned playTimePerFrame)
: FramedSource(env),
fPreferredFrameSize(fMaxSize),
fPlayTimePerFrame(playTimePerFrame),
fLastPlayTime(0),
fCurIndex(0)
{
if (referenceCount == 0)
{

}
++referenceCount;

x264_param_default_preset(&param, "veryfast", "zerolatency");
param.i_threads = 1;
param.i_width = 720;
param.i_height = 960;
param.i_fps_num = 60;
param.i_fps_den = 1;
// Intra refres:
param.i_keyint_max = 60;
param.b_intra_refresh = 1;
//Rate control:
param.rc.i_rc_method = X264_RC_CRF;
param.rc.f_rf_constant = 25;
param.rc.f_rf_constant_max = 35;
param.i_sps_id = 7;
//For streaming:
param.b_repeat_headers = 1;
param.b_annexb = 1;
x264_param_apply_profile(&param, "baseline");


encoder = x264_encoder_open(&param);
pic_in.i_type = X264_TYPE_AUTO;
pic_in.i_qpplus1 = 0;
pic_in.img.i_csp = X264_CSP_I420;
pic_in.img.i_plane = 3;


x264_picture_alloc(&pic_in, X264_CSP_I420, 720, 920);

convertCtx = sws_getContext(720, 960, PIX_FMT_RGB24, 720, 760, PIX_FMT_YUV420P, SWS_FAST_BILINEAR, NULL, NULL, NULL);


if (eventTriggerId == 0)
{
eventTriggerId = envir().taskScheduler().createEventTrigger(deliverFrame0);
}
}

H264FramedSource::~H264FramedSource()
{
--referenceCount;
if (referenceCount == 0)
{
// Reclaim our 'event trigger'
envir().taskScheduler().deleteEventTrigger(eventTriggerId);
eventTriggerId = 0;
}
}

void H264FramedSource::AddToBuffer(uint8_t* buf, int surfaceSizeInBytes)
{
uint8_t* surfaceData = (new uint8_t[surfaceSizeInBytes]);

memcpy(surfaceData, buf, surfaceSizeInBytes);

int srcstride = W*3;
sws_scale(convertCtx, &surfaceData, &srcstride,0, H, pic_in.img.plane, pic_in.img.i_stride);
x264_nal_t* nals = NULL;
int i_nals = 0;
int frame_size = -1;


frame_size = x264_encoder_encode(encoder, &nals, &i_nals, &pic_in, &pic_out);

static bool finished = false;

if (frame_size >= 0)
{
static bool alreadydone = false;
if(!alreadydone)
{

x264_encoder_headers(encoder, &nals, &i_nals);
alreadydone = true;
}
for(int i = 0; i < i_nals; ++i)
{
m_queue.push(nals[i]);
}
}
delete [] surfaceData;
surfaceData = NULL;

envir().taskScheduler().triggerEvent(eventTriggerId, this);
}

void H264FramedSource::doGetNextFrame()
{
deliverFrame();
}

void H264FramedSource::deliverFrame0(void* clientData)
{
((H264FramedSource*)clientData)->deliverFrame();
}

void H264FramedSource::deliverFrame()
{
x264_nal_t nalToDeliver;

if (fPlayTimePerFrame > 0 && fPreferredFrameSize > 0) {
if (fPresentationTime.tv_sec == 0 && fPresentationTime.tv_usec == 0) {
// This is the first frame, so use the current time:
gettimeofday(&fPresentationTime, NULL);
} else {
// Increment by the play time of the previous data:
unsigned uSeconds = fPresentationTime.tv_usec + fLastPlayTime;
fPresentationTime.tv_sec += uSeconds/1000000;
fPresentationTime.tv_usec = uSeconds%1000000;
}

// Remember the play time of this data:
fLastPlayTime = (fPlayTimePerFrame*fFrameSize)/fPreferredFrameSize;
fDurationInMicroseconds = fLastPlayTime;
} else {
// We don't know a specific play time duration for this data,
// so just record the current time as being the 'presentation time':
gettimeofday(&fPresentationTime, NULL);
}

if(!m_queue.empty())
{
m_queue.wait_and_pop(nalToDeliver);

uint8_t* newFrameDataStart = (uint8_t*)0xD15EA5E;

newFrameDataStart = (uint8_t*)(nalToDeliver.p_payload);
unsigned newFrameSize = nalToDeliver.i_payload;

// Deliver the data here:
if (newFrameSize > fMaxSize) {
fFrameSize = fMaxSize;
fNumTruncatedBytes = newFrameSize - fMaxSize;
}
else {
fFrameSize = newFrameSize;
}

memcpy(fTo, nalToDeliver.p_payload, nalToDeliver.i_payload);

FramedSource::afterGetting(this);
}
}

哦,对于那些想知道我的并发队列是什么的人来说,就在这里,它工作得很好 http://www.justsoftwaresolutions.co.uk/threading/implementing-a-thread-safe-queue-using-condition-variables.html

祝你好运!

关于c++ - 如何编写 Live555 FramedSource 以允许我直播 H.264,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13863673/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com