C++ 如何使用FFMPEG设置从RTSP流保存的视频的开始时间
我使用FFMPEG从RTSP流录制视频。我的代码所做的是获取当前日期时间,创建一个具有此格式的文件夹C++ 如何使用FFMPEG设置从RTSP流保存的视频的开始时间,c++,ffmpeg,record,rtsp,C++,Ffmpeg,Record,Rtsp,我使用FFMPEG从RTSP流录制视频。我的代码所做的是获取当前日期时间,创建一个具有此格式的文件夹年/月/日/小时/分钟,并将视频保存到该文件夹中 当新的分钟到达时,我根据新的分钟创建新文件夹,并将记录再次运行到新文件夹。 基本上它可以工作,但下一个视频开始时间是继续上一个视频的结束时间。例如: video1: 00:00 -> 00:55 video2: 00:56 -> ... 我希望我可以从00:00开始设置所有视频。我可以这样做吗 这是我的密码 ffmpeg.h clas
年/月/日/小时/分钟
,并将视频保存到该文件夹中
当新的分钟到达时,我根据新的分钟创建新文件夹,并将记录再次运行到新文件夹。
基本上它可以工作,但下一个视频开始时间是继续上一个视频的结束时间。例如:
video1: 00:00 -> 00:55
video2: 00:56 -> ...
我希望我可以从00:00开始设置所有视频。我可以这样做吗
这是我的密码
ffmpeg.h
class CtFfmpeg {
public:
CtFfmpeg();
~CtFfmpeg();
void init();
int getInput();
int getOutputName(const char *filename);
int release();
int ret;
AVFormatContext *ifmt_ctx, *ofmt_ctx;
AVStream *in_stream, *out_stream;
AVPacket pkt;
const char *in_filename;
char *out_filename;
private:
int setOutput(const char *outfilename);
AVOutputFormat *ofmt;
};
ffmpeg.cpp
#include "ctffmpeg.h"
CtFfmpeg::CtFfmpeg() {
in_filename = new char [1024];
out_filename = new char [1024];
}
CtFfmpeg::~CtFfmpeg() {
delete [] in_filename;
delete [] out_filename;
}
void CtFfmpeg::init() {
avcodec_register_all();
av_register_all();
avformat_network_init();
pkt = { 0 };
av_init_packet(&pkt);
ofmt = NULL;
ifmt_ctx = NULL;
ofmt_ctx = NULL;
return;
}
int CtFfmpeg::release() {
av_write_trailer(ofmt_ctx);
avcodec_close(out_stream->codec);
// avcodec_close(in_stream->codec);
// avformat_close_input(&ifmt_ctx);
/* close output */
if (!(ofmt->flags & AVFMT_NOFILE))
avio_close(ofmt_ctx->pb);
avformat_free_context(ofmt_ctx);
av_free_packet(&pkt);
if (ret < 0 && ret != AVERROR_EOF) {
fprintf(stderr, "Error occurred\n");
return 1;
}
}
int CtFfmpeg::getInput() {
if ((ret = avformat_open_input(&ifmt_ctx, in_filename, 0, 0)) < 0) {
fprintf(stderr, "Could not open input file '%s'", in_filename);
release();
}
if ((ret = avformat_find_stream_info(ifmt_ctx, 0)) < 0) {
fprintf(stderr, "Failed to retrieve input stream information");
release();
}
av_dump_format(ifmt_ctx, 0, in_filename, 0);
}
int CtFfmpeg::setOutput(const char *outfilename) {
avformat_alloc_output_context2(&ofmt_ctx, NULL, NULL, outfilename);
if (!ofmt_ctx) {
fprintf(stderr, "Could not create output context\n");
ret = AVERROR_UNKNOWN;
release();
}
ofmt = ofmt_ctx->oformat;
for (int i = 0; i < ifmt_ctx->nb_streams; i++) {
in_stream = ifmt_ctx->streams[i];
out_stream = avformat_new_stream(ofmt_ctx, in_stream->codec->codec);
if (!out_stream) {
fprintf(stderr, "Failed allocating output stream\n");
ret = AVERROR_UNKNOWN;
release();
}
ret = avcodec_copy_context(out_stream->codec, in_stream->codec);
if (ret < 0) {
fprintf(stderr, "Failed to copy context from input to output stream codec context\n");
release();
}
out_stream->codec->codec_tag = 0;
if (ofmt_ctx->oformat->flags & AVFMT_GLOBALHEADER)
out_stream->codec->flags |= CODEC_FLAG_GLOBAL_HEADER;
} // for
av_dump_format(ofmt_ctx, 0, outfilename, 1);
if (!(ofmt->flags & AVFMT_NOFILE)) {
ret = avio_open(&ofmt_ctx->pb, outfilename, AVIO_FLAG_WRITE);
if (ret < 0) {
fprintf(stderr, "Could not open output file '%s'", outfilename);
release();
}
}
ret = avformat_write_header(ofmt_ctx, NULL);
if (ret < 0) {
fprintf(stderr, "Error occurred when opening output file\n");
release();
}
}
int CtFfmpeg::getOutputName(const char *filename){
sprintf(out_filename,filename);
setOutput(out_filename);
}
#包括“ctffmpeg.h”
CtFfmpeg::CtFfmpeg(){
in_filename=新字符[1024];
out_filename=新字符[1024];
}
CtFfmpeg::~CtFfmpeg(){
删除文件名中的[];
删除[]文件名;
}
void CtFfmpeg::init(){
avcodec_寄存器_all();
av_寄存器_all();
avformat_network_init();
pkt={0};
av_初始_数据包(&pkt);
ofmt=NULL;
如果mt_ctx=NULL;
ofmt_ctx=NULL;
返回;
}
int-CtFfmpeg::release(){
av_写入_预告片(ofmt_ctx);
avcodec_关闭(输出流->编解码器);
//avcodec\u关闭(在\u流->编解码器中);
//AV格式\关闭\输入(&ifmt\ ctx);
/*关闭输出*/
if(!(ofmt->flags&AVFMT_NOFILE))
avio_关闭(ofmt_ctx->pb);
avformat_free_上下文(ofmt_ctx);
av_免费_数据包(&pkt);
if(ret<0&&ret!=AVERROR\u EOF){
fprintf(stderr,“出错\n”);
返回1;
}
}
int-CtFfmpeg::getInput(){
if((ret=avformat\u open\u input(&ifmt\u ctx,in\u filename,0,0))<0){
fprintf(stderr,“无法在文件名中打开输入文件“%s”);
释放();
}
如果((ret=avformat\u find\u stream\u info(ifmt\u ctx,0))<0){
fprintf(stderr,“检索输入流信息失败”);
释放();
}
av_dump_格式(ifmt_ctx,0,in_文件名,0);
}
int-CtFfmpeg::setOutput(常量字符*outfilename){
avformat_alloc_output_context2(&ofmt_ctx,NULL,NULL,outfilename);
如果(!ofmt_ctx){
fprintf(stderr,“无法创建输出上下文\n”);
ret=平均误差(未知);
释放();
}
ofmt=ofmt_ctx->oformat;
对于(int i=0;inb\u streams;i++){
in_stream=ifmt_ctx->streams[i];
out\u stream=avformat\u new\u stream(ofmt\u ctx,in\u stream->codec->codec);
如果(!流出){
fprintf(stderr,“分配输出流失败\n”);
ret=平均误差(未知);
释放();
}
ret=avcodec\u copy\u上下文(出流->编解码器,入流->编解码器);
如果(ret<0){
fprintf(stderr,“无法将上下文从输入复制到输出流编解码器上下文\n”);
释放();
}
out\u stream->codec->codec\u tag=0;
if(ofmt_ctx->oformat->flags和AVFMT_GLOBALHEADER)
out_stream->codec->flags |=codec_FLAG_GLOBAL_头;
}//为了
av_转储_格式(ofmt_ctx,0,输出文件名,1);
if(!(ofmt->flags&AVFMT_NOFILE)){
ret=avio_打开(&ofmt_ctx->pb,输出文件名,avio_标志_写入);
如果(ret<0){
fprintf(stderr,“无法打开输出文件“%s”,outfilename);
释放();
}
}
ret=avformat\U write\U头(ofmt\U ctx,NULL);
如果(ret<0){
fprintf(stderr,“打开输出文件时出错\n”);
释放();
}
}
int CtFfmpeg::getOutputName(常量字符*文件名){
sprintf(out_文件名,文件名);
设置输出(输出文件名);
}
main.cpp
#include "ctfolder.h"
#include "ctffmpeg.h"
CtFfmpeg * ff;
int main(int argc, char** argv) {
if (argc < 2) {
printf("usage: %s <RTSP link> \n", argv[0]);
return 1;
}
ff = new CtFfmpeg();
ff->in_filename = argv[1]; //RTSP input link
ff->init();
ff->getInput();
string filename;
videoRecorder obj;
int start, now;
start = obj.get_current_min();
if(obj.create_folder(0755))
cout << "Cannot create folder, maybe it already exists" << endl;
else
cout << "Create folder succesfully" << endl;
int skip = 0;
while(1){
filename = obj.update_filename();
ff->getOutputName(filename.c_str());
while((now = obj.get_current_min()) == start) {
ff->ret = av_read_frame(ff->ifmt_ctx, &(ff->pkt));
skip++;
if(skip==1)
continue;
if(skip>2)
skip=2;
if (ff->ret < 0)
continue;
ff->pkt.pts = av_rescale_q_rnd(ff->pkt.pts, ff->in_stream->time_base, ff->out_stream->time_base, (AVRounding)(AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX));
ff->pkt.dts = av_rescale_q_rnd(ff->pkt.dts, ff->in_stream->time_base, ff->out_stream->time_base, (AVRounding)(AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX));
ff->pkt.duration = av_rescale_q(ff->pkt.duration, ff->in_stream->time_base, ff->out_stream->time_base);
ff->pkt.pos = -1;
ff->ret = av_interleaved_write_frame(ff->ofmt_ctx, &(ff->pkt));
if (ff->ret < 0) {
fprintf(stderr, "Error muxing packet\n");
continue;
}
av_free_packet(&(ff->pkt));
}
ff->release();
cout << "New minute!" << endl;
if(obj.create_folder(0755))
cout << "Cannot create folder, something's wrong" << endl;
else
cout << "Create folder succesfully" << endl;
start = now;
}
return 0;
}
#包括“ctfolder.h”
#包括“ctffmpeg.h”
CtFfmpeg*ff;
int main(int argc,字符**argv){
如果(argc<2){
printf(“用法:%s\n”,argv[0]);
返回1;
}
ff=新的CtFfmpeg();
ff->in_filename=argv[1];//RTSP输入链接
ff->init();
ff->getInput();
字符串文件名;
录像机;
现在开始;
start=obj.get_current_min();
if(对象创建文件夹(0755))
cout-pkt);
skip++;
如果(跳过==1)
继续;
如果(跳过>2)
skip=2;
如果(ff->ret<0)
继续;
ff->pkt.pts=av_rescale_q_rnd(ff->pkt.pts,ff->in_stream->time_base,ff->out_stream->time_base,(AVRounding)(av_ROUND_INF|av ROUND_PASS_MINMAX)附近的av_ROUND_;
ff->pkt.dts=av_rescale_q_rnd(ff->pkt.dts,ff->in_stream->time_base,ff->out_stream->time_base,(avround)(av_ROUND_INF附近的av_ROUND_PASS_MINMAX));
ff->pkt.duration=av\u rescale\u q(ff->pkt.duration,ff->in\u stream->time\u base,ff->out\u stream->time\u base);
ff->pkt.pos=-1;
ff->ret=av_交错_写入_帧(ff->ofmt_ctx,&(ff->pkt));
如果(ff->ret<0){
fprintf(stderr,“错误多路复用数据包\n”);
继续;
}
av_-free_数据包(&(ff->pkt));
}
ff->release();
您是否需要将录制数据包的pts
转换为0
while(<some condition>)
{
//...
int64_t pts_offset = AV_NOPTS_VALUE ;
while((now = obj.get_current_min()) == start)
{
//...
ff.pkt.pts = ...
//...
if( pts_offset == AV_NOPTS_VALUE )
{
pts_offset = ff.pkt.pts ;
}
ff.pkt.pts -= pts_offset ;
// ...
}
}
while()
{
//...
int64点偏移=AV点偏移值;
while((now=obj.get_current_min())==start)
{
//...
ff.pkt.pts=。。。
//...
if(pts\U偏移==AV\U NOPTS\U值)
{
pts_offset=ff.pkt.pts;
}
ff.pkt.pts-=pts_偏移量;
// ...
}
}