ffmpeg 推流代码
时间: 2023-06-29 12:15:39 浏览: 65
以下是使用ffmpeg进行推流的基本代码示例:
```c
#include <stdio.h>
#include <libavformat/avformat.h>
#include <libavutil/opt.h>
int main(int argc, char **argv) {
AVFormatContext *fmt_ctx = NULL;
AVOutputFormat *out_fmt = NULL;
AVStream *out_stream = NULL;
AVCodec *codec = NULL;
AVCodecContext *codec_ctx = NULL;
AVDictionary *opt = NULL;
int ret, i;
// 初始化网络模块
avformat_network_init();
// 创建输出格式上下文
ret = avformat_alloc_output_context2(&fmt_ctx, NULL, "flv", "url_or_file_path");
if (ret < 0) {
fprintf(stderr, "Failed to create output context: %s\n", av_err2str(ret));
return ret;
}
// 获取输出格式
out_fmt = fmt_ctx->oformat;
// 添加视频流
codec = avcodec_find_encoder(out_fmt->video_codec);
if (!codec) {
fprintf(stderr, "Codec not found\n");
return AVERROR(EINVAL);
}
out_stream = avformat_new_stream(fmt_ctx, NULL);
if (!out_stream) {
fprintf(stderr, "Failed allocating output stream\n");
return AVERROR_UNKNOWN;
}
codec_ctx = avcodec_alloc_context3(codec);
if (!codec_ctx) {
fprintf(stderr, "Failed to allocate codec context\n");
return AVERROR(ENOMEM);
}
codec_ctx->codec_id = out_fmt->video_codec;
codec_ctx->bit_rate = 400000;
codec_ctx->width = 640;
codec_ctx->height = 480;
codec_ctx->time_base = (AVRational) {1, 25};
codec_ctx->gop_size = 10;
codec_ctx->max_b_frames = 1;
codec_ctx->pix_fmt = AV_PIX_FMT_YUV420P;
if (fmt_ctx->oformat->flags & AVFMT_GLOBALHEADER) {
codec_ctx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
}
ret = avcodec_open2(codec_ctx, codec, &opt);
if (ret < 0) {
fprintf(stderr, "Failed to open codec: %s\n", av_err2str(ret));
return ret;
}
ret = avcodec_parameters_from_context(out_stream->codecpar, codec_ctx);
if (ret < 0) {
fprintf(stderr, "Failed to copy codec parameters to output stream: %s\n", av_err2str(ret));
return ret;
}
// 打开输出流
ret = avio_open(&fmt_ctx->pb, "url_or_file_path", AVIO_FLAG_WRITE);
if (ret < 0) {
fprintf(stderr, "Failed to open output file: %s\n", av_err2str(ret));
return ret;
}
// 写入文件头
ret = avformat_write_header(fmt_ctx, &opt);
if (ret < 0) {
fprintf(stderr, "Failed to write header: %s\n", av_err2str(ret));
return ret;
}
// 循环写入视频帧
for (i = 0; i < 1000; i++) {
AVPacket pkt = {0};
av_init_packet(&pkt);
pkt.data = NULL;
pkt.size = 0;
ret = avcodec_send_frame(codec_ctx, frame);
if (ret < 0) {
fprintf(stderr, "Error sending a frame for encoding: %s\n", av_err2str(ret));
break;
}
while (ret >= 0) {
ret = avcodec_receive_packet(codec_ctx, &pkt);
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
break;
else if (ret < 0) {
fprintf(stderr, "Error during encoding: %s\n", av_err2str(ret));
break;
}
av_packet_rescale_ts(&pkt, codec_ctx->time_base, out_stream->time_base);
pkt.stream_index = out_stream->index;
ret = av_interleaved_write_frame(fmt_ctx, &pkt);
if (ret < 0) {
fprintf(stderr, "Error writing video frame: %s\n", av_err2str(ret));
break;
}
av_packet_unref(&pkt);
}
}
// 写入文件尾
av_write_trailer(fmt_ctx);
// 清理资源
avcodec_free_context(&codec_ctx);
avformat_close_input(&fmt_ctx);
return 0;
}
```
在示例代码中,我们使用了ffmpeg库中的AVFormatContext、AVOutputFormat、AVStream、AVCodec、AVCodecContext等结构体来完成推流过程。其中,AVFormatContext是格式上下文,用于存储输出格式的相关信息;AVOutputFormat是输出格式;AVStream是输出流,用于存储视频流的相关信息;AVCodec是编码器;AVCodecContext是编码器上下文,用于存储编码器的相关信息。
示例代码中,我们首先初始化了网络模块,然后创建了输出格式上下文,并获取了输出格式。接着,我们添加了视频流,并设置了视频流的相关参数。然后,我们打开了输出流,并写入了文件头。在循环中,我们发送视频帧到编码器中进行编码,然后将编码后的数据写入输出流中。最后,我们写入了文件尾,并清理了资源。
需要注意的是,示例代码中的url_or_file_path需要替换成你要推流的目标地址,可以是rtmp协议,也可以是文件路径等。另外,示例代码中的AVFrame frame需要自行准备并填充数据。