使用 ffmpeg 从 C++ 内存中的多个图像流式传输 RTSP
Posted
技术标签:
【中文标题】使用 ffmpeg 从 C++ 内存中的多个图像流式传输 RTSP【英文标题】:Streaming RTSP from multiple images from memory in C++ using ffmpeg 【发布时间】:2021-12-26 05:00:02 【问题描述】:我正在编写一个在屏幕上显示文本的应用程序。我希望能够通过 RTSP 流式传输屏幕(带有文本),以便像 OBS/vMix 或 VLC 这样的程序可以捕获它。我要做的是每 N 毫秒(比如每 100 毫秒)截取一次屏幕截图,将其保存到内存(而不是磁盘)中,然后将其写入到 ffmpeg
的管道中。然后ffmpeg
获取这些图像并从中生成 RTSP 流。我已经实现了每 N 毫秒截取一次屏幕截图的部分,并将其写入管道(类似于this 问题,不同之处在于我将图像保存在内存中,而不是磁盘上)。现在的问题是我对ffmpeg
不太了解(我已将参数设置为this 问题的答案,但是当我尝试通过VLC 或其他程序播放流时,屏幕上什么也看不到)。我可以在日志中看到很多Successfully sent a screenshot
,但在实际流中什么也没有。你能告诉我我做错了什么吗?
你可以找到整个项目here
这是我的(部分)代码:
bool RTSP_SERVER_SHOULD_START = false;
tthread::mutex rtsp_server_mutex;
tthread::mutex screenshot_mutex;
tthread::thread* rtsp;
FILE *pPipe;
bool send_screenshot = false;
int main(int argc, char *argv[])
// OpenGL stuff...
rtsp_server_mutex.lock();
if (RTSP_SERVER_SHOULD_START)
RTSP_SERVER_SHOULD_START = false;
rtsp = new tthread::thread(rtspScreenShotToPipe, 0);
if( (pPipe = _popen( "ffmpeg -re -f image2pipe -vcodec mjpeg -i - -vcodec h264 -r 10 -f mpegts udp://127.0.0.1:1234", "wb")) == NULL )
cerr << "Error: Could not open ffmpeg" << endl;
_pclose(pPipe);
exit(1);
rtsp_server_mutex.unlock();
while (!glfwWindowShouldClose(WINDOW))
// More OpenGL stuff
screenshot_mutex.lock();
if(send_screenshot)
send_screenshot = false;
// Make the BYTE array, factor of 3 because it's RBG.
BYTE* pixels = new BYTE[3 * DEFAULT_MONITOR.maxResolution.width * DEFAULT_MONITOR.maxResolution.height];
glReadPixels(0, 0, DEFAULT_MONITOR.maxResolution.width, DEFAULT_MONITOR.maxResolution.height, GL_RGB, GL_UNSIGNED_BYTE, pixels);
// Convert to FreeImage format & save to file
FIBITMAP* image = FreeImage_ConvertFromRawBits(pixels, DEFAULT_MONITOR.maxResolution.width, DEFAULT_MONITOR.maxResolution.height, 3 * DEFAULT_MONITOR.maxResolution.width, 24, 0x0000FF, 0xFF0000, 0x00FF00, false);
FreeImageIO io;
SetDefaultIO(&io);
bool success = FreeImage_SaveToHandle(FIF_JPEG, image, &io, (fi_handle)pPipe);
fflush(pPipe);
if(success)
cout << "Successfully sent a screenshot" << endl;
// Free resources
FreeImage_Unload(image);
delete [] pixels;
screenshot_mutex.unlock();
printf("%d", glGetError());
glfwTerminate();
return 0;
void rtspScreenShotToPipe(void * aArg)
while(true)
rtsp_server_mutex.try_lock();
if(!RTSP_SERVER_STARTED)
break;
rtsp_server_mutex.unlock();
tthread::this_thread::sleep_for(tthread::chrono::milliseconds(100));
screenshot_mutex.try_lock();
send_screenshot = true;
screenshot_mutex.unlock();
// I've copied those function from FreeImage in my code
void SetDefaultIO(FreeImageIO *io)
io->read_proc = _ReadProc;
io->seek_proc = _SeekProc;
io->tell_proc = _TellProc;
io->write_proc = _WriteProc;
unsigned DLL_CALLCONV _ReadProc(void *buffer, unsigned size, unsigned count, fi_handle handle)
return (unsigned)fread(buffer, size, count, (FILE *)handle);
unsigned DLL_CALLCONV _WriteProc(void *buffer, unsigned size, unsigned count, fi_handle handle)
return (unsigned)fwrite(buffer, size, count, (FILE *)handle);
int DLL_CALLCONV _SeekProc(fi_handle handle, long offset, int origin)
return fseek((FILE *)handle, offset, origin);
long DLL_CALLCONV _TellProc(fi_handle handle)
return ftell((FILE *)handle);
【问题讨论】:
【参考方案1】:您没有使用 RTSP,而是通过 UDP 发送 MPEG-TS。
在 VLC 中确保您侦听正确的网络流:
udp://@127.0.0.1:1234
在 FFmpeg 方面,您需要指定有效负载大小:
-f mpegts udp://127.0.0.1:1234?pkt_size=1316
FFmpeg 有一个可以直接从 C++ 使用的 API,因此您不必通过管道传输到进程。
【讨论】:
那个 API 是什么?有链接吗? @bennyb 文档:ffmpeg.org/doxygen/trunk/index.html,示例:ffmpeg.org/doxygen/trunk/examples.html 非常感谢!知道我是否可以流式传输到 RTSP 而不是 UDP?如果是,怎么做? @bennyb 你需要一个 RTSP 服务器。请参阅ffmpeg.org/ffmpeg-protocols.html#rtsp 了解更多信息。 非常感谢!以上是关于使用 ffmpeg 从 C++ 内存中的多个图像流式传输 RTSP的主要内容,如果未能解决你的问题,请参考以下文章
ffmpeg 在尝试用图像制作幻灯片时抛出“输出文件 #0 不包含任何流”