如何使用FFMPEG设置从RTSP流保存的视频的开始时间 [英] How to set start time of video saved from RTSP stream with FFMPEG

查看:339
本文介绍了如何使用FFMPEG设置从RTSP流保存的视频的开始时间的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我使用FFMPEG录制RTSP流中的视频.我的代码要做的是获取当前时间,创建一个格式为year/month/day/hour/minute的文件夹,并将视频保存到该文件夹​​.

I use FFMPEG to record video from a RTSP stream. What my code does is get current day time, create a folder with this format year/month/day/hour/minute and save the video to that folder.

到达新的分钟后,我将在新的分钟的基础上创建新的文件夹,并将记录再次运行到新的文件夹. 基本上可以,但是下一个视频的开始时间是上一个视频的结束时间.例如:

When a new minute arrive, I create the new folder base on the new minute and run the record again to the new folder. Basically It works, but the next video start time is continue the end of previous video. For example:

video1: 00:00 -> 00:55
video2: 00:56 -> ...

我希望我可以为所有视频设置从00:00开始.我可以这样做吗?

I hope I can set for all videos start from 00:00. Can I do that?

这是我的代码

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

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);
}

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;
}

推荐答案

您需要将记录包的pts转换为0.

You need to shift your recording packet's pts to 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 ;
        // ...
    }
}

这篇关于如何使用FFMPEG设置从RTSP流保存的视频的开始时间的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆