【问题标题】:Streaming RTSP from multiple images from memory in C++ using ffmpeg使用 ffmpeg 从 C++ 内存中的多个图像流式传输 RTSP
【发布时间】: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);
}

【问题讨论】:

    标签: c++ ffmpeg rtsp


    【解决方案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,因此您不必通过管道传输到进程。

    【讨论】:

    猜你喜欢
    • 2020-06-05
    • 2022-06-23
    • 2021-10-03
    • 1970-01-01
    • 2018-08-06
    • 2015-01-15
    • 2015-10-05
    • 2015-06-24
    • 2014-11-17
    相关资源
    最近更新 更多