C++ 如何使用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

我使用FFMPEG从RTSP流录制视频。我的代码所做的是获取当前日期时间,创建一个具有此格式的文件夹
年/月/日/小时/分钟
,并将视频保存到该文件夹中

当新的分钟到达时,我根据新的分钟创建新文件夹,并将记录再次运行到新文件夹。 基本上它可以工作,但下一个视频开始时间是继续上一个视频的结束时间。例如:

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_偏移量;
// ...
}
}