FFmpeg推流 跳转到指定位置的代码
时间: 2023-12-15 17:07:22 浏览: 121
在 FFmpeg 中进行推流并跳转到指定位置,需要先设置起始时间,并在推流时使用 `-ss` 参数来指定起始时间。以下是一个简单的示例代码:
```c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libavutil/avutil.h>
int main(int argc, char **argv) {
int ret;
AVFormatContext *ifmt_ctx;
AVFormatContext *ofmt_ctx;
AVPacket pkt;
int stream_index;
int i;
av_register_all();
avcodec_register_all();
if (argc < 5) {
printf("Usage: %s input output start_time\n", argv[0]);
return -1;
}
// 打开输入文件
if ((ret = avformat_open_input(&ifmt_ctx, argv[1], 0, 0)) < 0) {
printf("Could not open input file '%s'\n", argv[1]);
return ret;
}
// 获取流信息
if ((ret = avformat_find_stream_info(ifmt_ctx, 0)) < 0) {
printf("Failed to retrieve input stream information\n");
return ret;
}
// 打印输入文件信息
av_dump_format(ifmt_ctx, 0, argv[1], 0);
// 创建输出文件上下文
if ((ret = avformat_alloc_output_context2(&ofmt_ctx, NULL, NULL, argv[2])) < 0) {
printf("Could not create output context\n");
return ret;
}
// 复制输入流到输出流
for (i = 0; i < ifmt_ctx->nb_streams; i++) {
AVStream *in_stream = ifmt_ctx->streams[i];
AVStream *out_stream = avformat_new_stream(ofmt_ctx, in_stream->codec->codec);
if (!out_stream) {
printf("Failed allocating output stream\n");
return -1;
}
stream_index = i;
if ((ret = avcodec_copy_context(out_stream->codec, in_stream->codec)) < 0) {
printf("Failed to copy context from input to output stream codec context\n");
return ret;
}
out_stream->codec->codec_tag = 0;
if (ofmt_ctx->oformat->flags & AVFMT_GLOBALHEADER) {
out_stream->codec->flags |= CODEC_FLAG_GLOBAL_HEADER;
}
}
// 打开输出文件
if (!(ofmt_ctx->oformat->flags & AVFMT_NOFILE)) {
if ((ret = avio_open(&ofmt_ctx->pb, argv[2], AVIO_FLAG_WRITE)) < 0) {
printf("Could not open output file '%s'\n", argv[2]);
return ret;
}
}
// 写文件头
if ((ret = avformat_write_header(ofmt_ctx, NULL)) < 0) {
printf("Error occurred when opening output file\n");
return ret;
}
// 设置起始时间
int64_t start_time = atoi(argv[3]) * AV_TIME_BASE;
// 查找最小时间戳
int64_t min_pts = INT64_MAX;
for (i = 0; i < ifmt_ctx->nb_streams; i++) {
AVStream *in_stream = ifmt_ctx->streams[i];
if (in_stream->start_time != AV_NOPTS_VALUE && in_stream->start_time < min_pts) {
min_pts = in_stream->start_time;
}
}
// 从指定位置开始推流
while (1) {
AVStream *in_stream, *out_stream;
ret = av_read_frame(ifmt_ctx, &pkt);
if (ret < 0) {
break;
}
if (pkt.pts < start_time) {
av_packet_unref(&pkt);
continue;
}
in_stream = ifmt_ctx->streams[pkt.stream_index];
out_stream = ofmt_ctx->streams[pkt.stream_index];
// 转换时间戳
if (pkt.pts != AV_NOPTS_VALUE) {
pkt.pts -= min_pts;
}
if (pkt.dts != AV_NOPTS_VALUE) {
pkt.dts -= min_pts;
}
if (pkt.duration > 0) {
pkt.duration = av_rescale_q(pkt.duration, in_stream->time_base, out_stream->time_base);
}
pkt.pos = -1;
// 写入输出文件
ret = av_interleaved_write_frame(ofmt_ctx, &pkt);
if (ret < 0) {
printf("Error muxing packet\n");
break;
}
av_packet_unref(&pkt);
}
// 写文件尾
av_write_trailer(ofmt_ctx);
// 关闭输入文件
avformat_close_input(&ifmt_ctx);
// 关闭输出文件
if (ofmt_ctx && !(ofmt_ctx->oformat->flags & AVFMT_NOFILE)) {
avio_closep(&ofmt_ctx->pb);
}
avformat_free_context(ofmt_ctx);
return 0;
}
```
在示例代码中,使用 `avformat_open_input` 打开输入文件,然后使用 `avformat_find_stream_info` 获取流信息。接着,使用 `avformat_alloc_output_context2` 创建输出文件上下文,并复制输入流到输出流。使用 `avio_open` 打开输出文件,然后使用 `avformat_write_header` 写文件头。
在推流时,先设置起始时间,然后查找最小时间戳。使用 `av_read_frame` 读取输入文件中的帧,判断帧的时间戳是否在起始时间之后,如果是,则转换时间戳并写入输出文件。最后使用 `av_write_trailer` 写文件尾,并关闭输入和输出文件。
阅读全文