簡體   English   中英

如何設置從 RTSP stream 和 FFMPEG 保存的視頻的開始時間

[英]How to set start time of video saved from RTSP stream with FFMPEG

我使用 FFMPEG 從 RTSP stream 錄制視頻。我的代碼所做的是獲取當前日期時間,創建格式為year/month/day/hour/minute的文件夾並將視頻保存到該文件夾。

當新的分鍾到來時,我根據新的分鍾創建新的文件夾,然后再次運行記錄到新的文件夾。 基本上它有效,但下一個視頻開始時間是繼續上一個視頻的結束。 例如:

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

主.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

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

我嘗試構建您的代碼並向其中添加Alexander Chernin建議,但我遇到了 muxer 錯誤!

當你減少記錄包的pts時,它的值比記錄包的dts低go。 在 avcodec.h 中,上面的 pts 聲明我發現了這個評論:

pts 必須大於或等於 dts,因為演示不能在解壓縮之前發生。

我通過減少記錄數據包的 dts 解決了這個錯誤。

            ff->pkt.pts = av_rescale_q_rnd(ff->pkt.pts, ff->in_stream->ff->out_stream->(AVRounding) (AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX));
            if (pts_offset == AV_NOPTS_VALUE) {
                pts_offset = ff->pkt.pts;
            }
            ff->pkt.pts -= pts_offset;
            ff->pkt.dts -= pts_offset;
            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;

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM