pcm使用ffmpeg编码h264,然后用srs-librtmp推流 C++例子
时间: 2023-08-02 17:10:53 浏览: 263
以下是用ffmpeg编码h264并用srs-librtmp推流的C++例子:
```cpp
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <time.h>
#include <stdint.h>
#include <math.h>
#include <signal.h>
extern "C" {
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libavutil/opt.h>
#include <libavutil/imgutils.h>
#include <libavutil/mathematics.h>
#include <libavutil/time.h>
#include <libswscale/swscale.h>
#include <libswresample/swresample.h>
#include <librtmp/rtmp.h>
#include <librtmp/log.h>
}
#define W 640
#define H 480
#define FPS 30
#define BITRATE 500000
AVFormatContext *pFormatCtx;
AVOutputFormat *pOutputFmt;
AVStream *pVideoStream;
AVCodecContext *pVideoCodecCtx;
AVCodec *pVideoCodec;
AVFrame *pVideoFrame;
AVPacket videoPkt;
uint8_t *videoBuf;
SwsContext *pImgConvertCtx;
RTMP *pRtmp;
RTMPPacket rtmpPkt;
int64_t pts = 0;
void signal_handler(int signo)
{
if (signo == SIGINT) {
printf("Got SIGINT signal, exiting...\n");
exit(1);
}
}
void init_video_codec()
{
pVideoCodec = avcodec_find_encoder(AV_CODEC_ID_H264);
if (!pVideoCodec) {
fprintf(stderr, "Failed to find H.264 codec\n");
exit(1);
}
pVideoCodecCtx = avcodec_alloc_context3(pVideoCodec);
if (!pVideoCodecCtx) {
fprintf(stderr, "Failed to allocate H.264 codec context\n");
exit(1);
}
pVideoCodecCtx->bit_rate = BITRATE;
pVideoCodecCtx->width = W;
pVideoCodecCtx->height = H;
pVideoCodecCtx->time_base.num = 1;
pVideoCodecCtx->time_base.den = FPS;
pVideoCodecCtx->gop_size = FPS * 2;
pVideoCodecCtx->max_b_frames = 1;
pVideoCodecCtx->pix_fmt = AV_PIX_FMT_YUV420P;
if (pOutputFmt->flags & AVFMT_GLOBALHEADER)
pVideoCodecCtx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
av_opt_set(pVideoCodecCtx->priv_data, "preset", "ultrafast", 0);
av_opt_set(pVideoCodecCtx->priv_data, "tune", "zerolatency", 0);
if (avcodec_open2(pVideoCodecCtx, pVideoCodec, NULL) < 0) {
fprintf(stderr, "Failed to open H.264 codec\n");
exit(1);
}
pVideoFrame = av_frame_alloc();
if (!pVideoFrame) {
fprintf(stderr, "Failed to allocate video frame\n");
exit(1);
}
pVideoFrame->format = pVideoCodecCtx->pix_fmt;
pVideoFrame->width = pVideoCodecCtx->width;
pVideoFrame->height = pVideoCodecCtx->height;
if (av_frame_get_buffer(pVideoFrame, 32) < 0) {
fprintf(stderr, "Failed to allocate video frame buffer\n");
exit(1);
}
videoBuf = (uint8_t*)av_malloc(av_image_get_buffer_size(pVideoCodecCtx->pix_fmt, pVideoCodecCtx->width, pVideoCodecCtx->height, 1));
if (!videoBuf) {
fprintf(stderr, "Failed to allocate video buffer\n");
exit(1);
}
av_image_fill_arrays(pVideoFrame->data, pVideoFrame->linesize, videoBuf, pVideoCodecCtx->pix_fmt, pVideoCodecCtx->width, pVideoCodecCtx->height, 1);
}
void init_sws_context()
{
pImgConvertCtx = sws_getContext(pVideoCodecCtx->width, pVideoCodecCtx->height, AV_PIX_FMT_BGR24, pVideoCodecCtx->width, pVideoCodecCtx->height, pVideoCodecCtx->pix_fmt, SWS_BICUBIC, NULL, NULL, NULL);
if (!pImgConvertCtx) {
fprintf(stderr, "Failed to create SwsContext\n");
exit(1);
}
}
void init_output()
{
avformat_alloc_output_context2(&pFormatCtx, NULL, "flv", NULL);
if (!pFormatCtx) {
fprintf(stderr, "Failed to allocate output context\n");
exit(1);
}
pOutputFmt = pFormatCtx->oformat;
if (pOutputFmt->video_codec == AV_CODEC_ID_NONE) {
fprintf(stderr, "Failed to find suitable video codec\n");
exit(1);
}
init_video_codec();
init_sws_context();
pVideoStream = avformat_new_stream(pFormatCtx, pVideoCodec);
if (!pVideoStream) {
fprintf(stderr, "Failed to allocate video stream\n");
exit(1);
}
pVideoStream->id = 0;
pVideoStream->time_base.num = 1;
pVideoStream->time_base.den = FPS;
pVideoStream->codecpar->codec_id = pVideoCodec->id;
pVideoStream->codecpar->codec_type = AVMEDIA_TYPE_VIDEO;
pVideoStream->codecpar->width = W;
pVideoStream->codecpar->height = H;
pVideoStream->codecpar->format = pVideoCodecCtx->pix_fmt;
if (avformat_write_header(pFormatCtx, NULL) < 0) {
fprintf(stderr, "Failed to write header\n");
exit(1);
}
}
void init_rtmp(const char *url)
{
RTMP_LogSetLevel(RTMP_LOGDEBUG);
pRtmp = RTMP_Alloc();
if (!pRtmp) {
fprintf(stderr, "Failed to allocate RTMP object\n");
exit(1);
}
if (!RTMP_Init(pRtmp)) {
fprintf(stderr, "Failed to initialize RTMP object\n");
exit(1);
}
if (!RTMP_SetupURL(pRtmp, (char*)url)) {
fprintf(stderr, "Failed to set RTMP URL\n");
exit(1);
}
RTMP_EnableWrite(pRtmp);
if (!RTMP_Connect(pRtmp, NULL)) {
fprintf(stderr, "Failed to connect to RTMP server\n");
exit(1);
}
if (!RTMP_ConnectStream(pRtmp, 0)) {
fprintf(stderr, "Failed to connect to RTMP stream\n");
exit(1);
}
}
void cleanup()
{
av_write_trailer(pFormatCtx);
avcodec_free_context(&pVideoCodecCtx);
av_frame_free(&pVideoFrame);
av_free(videoBuf);
sws_freeContext(pImgConvertCtx);
RTMP_Close(pRtmp);
RTMP_Free(pRtmp);
avformat_free_context(pFormatCtx);
}
void encode_frame()
{
AVFrame *pFrameBGR24 = av_frame_alloc();
if (!pFrameBGR24) {
fprintf(stderr, "Failed to allocate BGR24 frame\n");
exit(1);
}
pFrameBGR24->format = AV_PIX_FMT_BGR24;
pFrameBGR24->width = W;
pFrameBGR24->height = H;
if (av_frame_get_buffer(pFrameBGR24, 32) < 0) {
fprintf(stderr, "Failed to allocate BGR24 frame buffer\n");
exit(1);
}
// generate test pattern
for (int y = 0; y < H; y++) {
for (int x = 0; x < W; x++) {
uint8_t r, g, b;
if (x < W / 2) {
r = 255 * x * 2 / W;
g = 255 * y / H;
b = 255 - 255 * x * 2 / W;
} else {
r = 255 - 255 * (x - W / 2) * 2 / W;
g = 255 - 255 * y / H;
b = 255 * (x - W / 2) * 2 / W;
}
pFrameBGR24->data[0][y * pFrameBGR24->linesize[0] + x * 3] = b;
pFrameBGR24->data[0][y * pFrameBGR24->linesize[0] + x * 3 + 1] = g;
pFrameBGR24->data[0][y * pFrameBGR24->linesize[0] + x * 3 + 2] = r;
}
}
sws_scale(pImgConvertCtx, pFrameBGR24->data, pFrameBGR24->linesize, 0, H, pVideoFrame->data, pVideoFrame->linesize);
av_init_packet(&videoPkt);
videoPkt.data = NULL;
videoPkt.size = 0;
pVideoFrame->pts = pts++;
int ret = avcodec_send_frame(pVideoCodecCtx, pVideoFrame);
if (ret < 0) {
fprintf(stderr, "Failed to send video frame: %s\n", av_err2str(ret));
exit(1);
}
while (ret >= 0) {
ret = avcodec_receive_packet(pVideoCodecCtx, &videoPkt);
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
break;
else if (ret < 0) {
fprintf(stderr, "Failed to receive video packet: %s\n", av_err2str(ret));
exit(1);
}
rtmpPkt.m_nChannel = 0x04;
rtmpPkt.m_headerType = RTMP_PACKET_TYPE_VIDEO;
rtmpPkt.m_nTimeStamp = videoPkt.pts * 1000 / FPS;
rtmpPkt.m_nBodySize = videoPkt.size;
rtmpPkt.m_nInfoField2 = pRtmp->m_stream_id;
rtmpPkt.m_body = videoPkt.data;
if (!RTMP_IsConnected(pRtmp))
break;
if (!RTMP_SendPacket(pRtmp, &rtmpPkt, TRUE)) {
fprintf(stderr, "Failed to send RTMP packet\n");
exit(1);
}
av_packet_unref(&videoPkt);
}
av_frame_free(&pFrameBGR24);
}
int main(int argc, char **argv)
{
if (argc < 2) {
printf("Usage: %s <rtmp url>\n", argv[0]);
exit(1);
}
init_output();
init_rtmp(argv[1]);
signal(SIGINT, signal_handler);
while (1) {
encode_frame();
usleep(1000000 / FPS);
}
cleanup();
return 0;
}
```
这个例子会生成一个测试图案并用ffmpeg编码成H.264,然后用srs-librtmp推流到指定的RTMP服务器上。你需要将代码中的推流地址替换为你自己的RTMP服务器地址。
阅读全文