参考ffmpeg官方协议文档:FFmpeg 协议文档
RTSP(Real-Time Streaming Protocol)和RTMP(Real-Time Messaging Protocol)都是用于实时流媒体传输的协议。
RTMP使用单一的持久连接(通常是TCP),在该连接上同时传输控制信息和媒体数据,其相对较灵活,支持多种编码格式和传输方式。最初设计用于Flash播放器,但后来也被其他应用广泛采用RTMP曾经在直播、在线视频等领域非常流行。然而,由于Adobe停止支持Flash Player,并且HTML5和其他技术的兴起,RTMP的使用逐渐减少。
使用以下命令推流到RTMP服务器,将 [RTMP_URL] 替换为实际的RTMP服务器地址。
ffmpeg -i input_video.mp4 -c:v libx264 -c:a aac -strict -2 -f flv [RTMP_URL]
ffmpeg -i [RTMP_URL] -c copy output_video.mp4
替换 [RTMP_URL] 为实际的RTMP服务器地址。这个地址通常以 rtmp:// 开头,后面是服务器地址和应用程序路径。
输入和输出文件的格式和编码参数可以根据您的需求进行调整。
在实际应用中,可能需要提供更多的参数,比如设置视频分辨率、码率、帧率等。
#include
#include
#include
#include
#include
#include
int main(int argc, char *argv[]) {
if (argc < 3) {
fprintf(stderr, "Usage: %s \n" , argv[0]);
return EXIT_FAILURE;
}
const char *input_file = argv[1];
const char *rtmp_url = argv[2];
av_register_all();
avformat_network_init();
AVFormatContext *input_ctx = NULL;
if (avformat_open_input(&input_ctx, input_file, NULL, NULL) != 0) {
fprintf(stderr, "Error opening input file\n");
return EXIT_FAILURE;
}
if (avformat_find_stream_info(input_ctx, NULL) < 0) {
fprintf(stderr, "Error finding stream information\n");
return EXIT_FAILURE;
}
AVOutputFormat *output_fmt = av_guess_format("flv", NULL, NULL);
if (!output_fmt) {
fprintf(stderr, "Error guessing output format\n");
return EXIT_FAILURE;
}
AVFormatContext *output_ctx = NULL;
if (avformat_alloc_output_context2(&output_ctx, output_fmt, NULL, rtmp_url) < 0) {
fprintf(stderr, "Error allocating output context\n");
return EXIT_FAILURE;
}
for (int i = 0; i < input_ctx->nb_streams; i++) {
AVStream *in_stream = input_ctx->streams[i];
AVStream *out_stream = avformat_new_stream(output_ctx, in_stream->codec->codec);
if (!out_stream) {
fprintf(stderr, "Error creating output stream\n");
return EXIT_FAILURE;
}
if (avcodec_copy_context(out_stream->codec, in_stream->codec) != 0) {
fprintf(stderr, "Error copying codec context\n");
return EXIT_FAILURE;
}
}
if (avio_open(&output_ctx->pb, rtmp_url, AVIO_FLAG_WRITE) < 0) {
fprintf(stderr, "Error opening output URL\n");
return EXIT_FAILURE;
}
if (avformat_write_header(output_ctx, NULL) < 0) {
fprintf(stderr, "Error writing header\n");
return EXIT_FAILURE;
}
AVPacket packet;
int frame_index = 0;
int64_t start_time = av_gettime();
while (1) {
AVStream *in_stream, *out_stream;
if (av_read_frame(input_ctx, &packet) < 0)
break;
in_stream = input_ctx->streams[packet.stream_index];
out_stream = output_ctx->streams[packet.stream_index];
packet.pts = av_rescale_q_rnd(packet.pts, in_stream->time_base, out_stream->time_base, AV_ROUND_NEAR_INF);
packet.dts = av_rescale_q_rnd(packet.dts, in_stream->time_base, out_stream->time_base, AV_ROUND_NEAR_INF);
packet.duration = av_rescale_q(packet.duration, in_stream->time_base, out_stream->time_base);
packet.pos = -1;
if (av_interleaved_write_frame(output_ctx, &packet) < 0) {
fprintf(stderr, "Error writing frame\n");
return EXIT_FAILURE;
}
printf("Write %8d frames to output URL\n", frame_index);
av_packet_unref(&packet);
frame_index++;
}
av_write_trailer(output_ctx);
avio_close(output_ctx->pb);
avformat_free_context(output_ctx);
avformat_close_input(&input_ctx);
return EXIT_SUCCESS;
}
#include
#include
#include
#include
int main(int argc, char *argv[]) {
if (argc < 3) {
fprintf(stderr, "Usage: %s \n" , argv[0]);
return EXIT_FAILURE;
}
const char *rtmp_url = argv[1];
const char *output_file = argv[2];
av_register_all();
avformat_network_init();
AVFormatContext *input_ctx = NULL;
if (avformat_open_input(&input_ctx, rtmp_url, NULL, NULL) != 0) {
fprintf(stderr, "Error opening input URL\n");
return EXIT_FAILURE;
}
if (avformat_find_stream_info(input_ctx, NULL) < 0) {
fprintf(stderr, "Error finding stream information\n");
return EXIT_FAILURE;
}
av_dump_format(input_ctx, 0, rtmp_url, 0);
AVFormatContext *output_ctx = NULL;
if (avformat_alloc_output_context2(&output_ctx, NULL, NULL, output_file) < 0) {
fprintf(stderr, "Error allocating output context\n");
return EXIT_FAILURE;
}
for (int i = 0; i < input_ctx->nb_streams; i++) {
AVStream *in_stream = input_ctx->streams[i];
AVStream *out_stream = avformat_new_stream(output_ctx, in_stream->codec->codec);
if (!out_stream) {
fprintf(stderr, "Error creating output stream\n");
return EXIT_FAILURE;
}
if (avcodec_copy_context(out_stream->codec, in_stream->codec) != 0) {
fprintf(stderr, "Error copying codec context\n");
return EXIT_FAILURE;
}
}
if (avio_open(&output_ctx->pb, output_file, AVIO_FLAG_WRITE) < 0) {
fprintf(stderr, "Error opening output file\n");
return EXIT_FAILURE;
}
if (avformat_write_header(output_ctx, NULL) < 0) {
fprintf(stderr, "Error writing header\n");
return EXIT_FAILURE;
}
AVPacket packet;
while (1) {
if (av_read_frame(input_ctx, &packet) < 0)
break;
AVStream *in_stream, *out_stream;
in_stream = input_ctx->streams[packet.stream_index];
out_stream = output_ctx->streams[packet.stream_index];
packet.pts = av_rescale_q_rnd(packet.pts, in_stream->time_base, out_stream->time_base, AV_ROUND_NEAR_INF);
packet.dts = av_rescale_q_rnd(packet.dts, in_stream->time_base, out_stream->time_base, AV_ROUND_NEAR_INF);
packet.duration = av_rescale_q(packet.duration, in_stream->time_base, out_stream->time_base);
packet.pos = -1;
if (av_interleaved_write_frame(output_ctx, &packet) < 0) {
fprintf(stderr, "Error writing frame\n");
return EXIT_FAILURE;
}
av_packet_unref(&packet);
}
av_write_trailer(output_ctx);
avio_close(output_ctx->pb);
avformat_free_context(output_ctx);
avformat_close_input(&input_ctx);
return EXIT_SUCCESS;
}
gcc push_to_rtmp_server.c -o push_to_rtmp_server -lavformat -lavcodec -lswscale -lavutil
gcc pull_from_rtmp_server.c -o pull_from_rtmp_server -lavformat -lavcodec -lswscale -lavutil
#执行服务端推流
./push_to_rtmp_server input_video.mp4 rtmp://example.com/live/stream
#执行客户端拉流
./pull_from_rtmp_server rtmp://example.com/live/stream output_video.mp4