gpt4 book ai didi

c++ - libav 生成具有极高帧速率的 MP4 文件

转载 作者:行者123 更新时间:2023-12-04 22:57:01 25 4
gpt4 key购买 nike

我正在尝试编写一个程序来生成要通过 ffmpeg/libav 编码到具有单个 h264 流的 mp4 文件的帧。我找到了这两个示例,并试图将它们合并在一起以制作我想要的:[ video transcoder ] [ raw MPEG1 encoder ]
我已经能够获得视频输出(绿色圆圈改变大小),但无论我如何设置帧的 PTS 值或 time_base我在 AVCodecContext 中指定或 AVStream ,我得到的帧速率约为 7000-15000 而不是 60,导致视频文件持续 70 毫秒而不是 1000 帧/60 fps = 166 秒。每次我更改一些代码时,帧速率都会发生一点变化,就好像它正在从未初始化的内存中读取一样。 StackOverflow 上对此类问题的其他引用似乎与错误设置的 PTS 值有关;但是,我尝试打印出我能找到的所有 PTS、DTS 和时基值,它们看起来都很正常。这是我的概念验证代码(为了清楚起见,删除了捕获 libav 调用周围的东西的错误):

#include <iostream>
#include <opencv2/opencv.hpp>
#include <math.h>

extern "C" {
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libavutil/opt.h>
#include <libavutil/timestamp.h>
}

using namespace cv;

int main(int argc, char *argv[]) {
const char *filename = "testvideo.mp4";

AVFormatContext *avfc;
avformat_alloc_output_context2(&avfc, NULL, NULL, filename);

AVStream *stream = avformat_new_stream(avfc, NULL);
AVCodec *h264 = avcodec_find_encoder(AV_CODEC_ID_H264);
AVCodecContext *avcc = avcodec_alloc_context3(h264);

av_opt_set(avcc->priv_data, "preset", "fast", 0);
av_opt_set(avcc->priv_data, "crf", "20", 0);
avcc->thread_count = 1;
avcc->width = 1920;
avcc->height = 1080;
avcc->pix_fmt = AV_PIX_FMT_YUV420P;
avcc->time_base = av_make_q(1, 60);
stream->time_base = avcc->time_base;

if(avfc->oformat->flags & AVFMT_GLOBALHEADER)
avcc->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;

avcodec_open2(avcc, h264, NULL);
avcodec_parameters_from_context(stream->codecpar, avcc);

avio_open(&avfc->pb, filename, AVIO_FLAG_WRITE);

avformat_write_header(avfc, NULL);

Mat frame, nothing = Mat::zeros(1080, 1920, CV_8UC1);
AVFrame *avf = av_frame_alloc();
AVPacket *avp = av_packet_alloc();
int ret;

avf->format = AV_PIX_FMT_YUV420P;
avf->width = 1920;
avf->height = 1080;
avf->linesize[0] = 1920;
avf->linesize[1] = 1920;
avf->linesize[2] = 1920;

for(int x=0; x<1000; x++) {
frame = Mat::zeros(1080, 1920, CV_8UC1);
circle(frame, Point(1920/2, 1080/2), 250*(sin(2*M_PI*x/1000*3)+1.01), Scalar(255), 10);

avf->data[0] = frame.data;
avf->data[1] = nothing.data;
avf->data[2] = nothing.data;
avf->pts = x;

ret = 0;
do {
if(ret == AVERROR(EAGAIN)) {
av_packet_unref(avp);
ret = avcodec_receive_packet(avcc, avp);
if(ret) break; // deal with error
av_write_frame(avfc, avp);
} //else if(ret) deal with error
ret = avcodec_send_frame(avcc, avf);
} while(ret);
}

// flush the rest of the packets
avcodec_send_frame(avcc, NULL);
do {
av_packet_unref(avp);
ret = avcodec_receive_packet(avcc, avp);
if(!ret)
av_write_frame(avfc, avp);
} while(!ret);

av_frame_free(&avf);
av_packet_free(&avp);

av_write_trailer(avfc);
avformat_close_input(&avfc);
avformat_free_context(avfc);
avcodec_free_context(&avcc);
return 0;
}
这是 ffprobe 的输出在输出视频文件上运行
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'testvideo.mp4':
Metadata:
major_brand : isom
minor_version : 512
compatible_brands: isomiso2avc1mp41
encoder : Lavf58.76.100
Duration: 00:00:00.07, start: 0.000000, bitrate: 115192 kb/s
Stream #0:0(und): Video: h264 (High) (avc1 / 0x31637661), yuv420p, 1920x1080, 115389 kb/s, 15375.38 fps, 15360 tbr, 15360 tbn, 120 tbc (default)
Metadata:
handler_name : VideoHandler
vendor_id : [0][0][0][0]
什么可能导致我的帧速率如此之高?提前感谢您的帮助。

最佳答案

由于您未能设置 数据包持续时间 ,因此您获得了高帧率。

  • time_base 设置为更高分辨率(如 1/60000),如 here 所述:
     avcc->time_base = av_make_q(1, 60000);
  • 设置 avp->duration 描述为 here :
     AVRational avg_frame_rate = av_make_q(60, 1);   //60 fps
    avp->duration = avcc->time_base.den / avcc->time_base.num / avg_frame_rate.num * avg_frame_rate.den; //avp->duration = 1000 (60000/60)
    并相应地设置 pts

  • 完整代码:
    #include <iostream>
    #include <opencv2/opencv.hpp>
    #include <math.h>

    extern "C" {
    #include <libavcodec/avcodec.h>
    #include <libavformat/avformat.h>
    #include <libavutil/opt.h>
    #include <libavutil/timestamp.h>
    }

    using namespace cv;

    int main(int argc, char* argv[]) {
    const char* filename = "testvideo.mp4";

    AVFormatContext* avfc;
    avformat_alloc_output_context2(&avfc, NULL, NULL, filename);

    AVStream* stream = avformat_new_stream(avfc, NULL);
    AVCodec* h264 = avcodec_find_encoder(AV_CODEC_ID_H264);
    AVCodecContext* avcc = avcodec_alloc_context3(h264);

    av_opt_set(avcc->priv_data, "preset", "fast", 0);
    av_opt_set(avcc->priv_data, "crf", "20", 0);
    avcc->thread_count = 1;
    avcc->width = 1920;
    avcc->height = 1080;
    avcc->pix_fmt = AV_PIX_FMT_YUV420P;
    //Sey the time_base to higher resolution like 1/60000
    avcc->time_base = av_make_q(1, 60000); //avcc->time_base = av_make_q(1, 60);
    stream->time_base = avcc->time_base;

    if (avfc->oformat->flags & AVFMT_GLOBALHEADER)
    avcc->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;

    avcodec_open2(avcc, h264, NULL);
    avcodec_parameters_from_context(stream->codecpar, avcc);

    avio_open(&avfc->pb, filename, AVIO_FLAG_WRITE);

    avformat_write_header(avfc, NULL);

    Mat frame, nothing = Mat::zeros(1080, 1920, CV_8UC1);
    AVFrame* avf = av_frame_alloc();
    AVPacket* avp = av_packet_alloc();
    int ret;

    avf->format = AV_PIX_FMT_YUV420P;
    avf->width = 1920;
    avf->height = 1080;
    avf->linesize[0] = 1920;
    avf->linesize[1] = 1920;
    avf->linesize[2] = 1920;

    for (int x = 0; x < 1000; x++) {
    frame = Mat::zeros(1080, 1920, CV_8UC1);
    circle(frame, Point(1920 / 2, 1080 / 2), (int)(250.0 * (sin(2 * M_PI * x / 1000 * 3) + 1.01)), Scalar(255), 10);

    AVRational avg_frame_rate = av_make_q(60, 1); //60 fps

    int64_t avp_duration = avcc->time_base.den / avcc->time_base.num / avg_frame_rate.num * avg_frame_rate.den;

    avf->data[0] = frame.data;
    avf->data[1] = nothing.data;
    avf->data[2] = nothing.data;
    avf->pts = (int64_t)x * avp_duration; // avp->duration = 1000

    ret = 0;
    do {
    if (ret == AVERROR(EAGAIN)) {
    av_packet_unref(avp);
    ret = avcodec_receive_packet(avcc, avp);
    if (ret) break; // deal with error

    ////////////////////////////////////////////////////////////////
    //avp->duration was zero.
    avp->duration = avp_duration; //avp->duration = 1000 (60000/60)

    //avp->pts = (int64_t)x * avp->duration;
    ////////////////////////////////////////////////////////////////

    av_write_frame(avfc, avp);
    } //else if(ret) deal with error
    ret = avcodec_send_frame(avcc, avf);
    } while (ret);
    }

    // flush the rest of the packets
    avcodec_send_frame(avcc, NULL);
    do {
    av_packet_unref(avp);
    ret = avcodec_receive_packet(avcc, avp);
    if (!ret)
    av_write_frame(avfc, avp);
    } while (!ret);

    av_frame_free(&avf);
    av_packet_free(&avp);

    av_write_trailer(avfc);
    avformat_close_input(&avfc);
    avformat_free_context(avfc);
    avcodec_free_context(&avcc);
    return 0;
    }

    FFprobe 的结果:
    Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'testvideo.mp4':
    Metadata:
    major_brand : isom
    minor_version : 512
    compatible_brands: isomiso2avc1mp41
    encoder : Lavf58.76.100
    Duration: 00:00:16.65, start: 0.000000, bitrate: 456 kb/s
    Stream #0:0(und): Video: h264 (High) (avc1 / 0x31637661), yuv420p, 1920x1080, 450 kb/s, 60.06 fps, 60 tbr, 60k tbn, 120k tbc (default)
    Metadata:
    handler_name : VideoHandler
    vendor_id : [0][0][0][0]

    笔记:
  • 我不知道为什么fps是60.06而不是60。
  • 有一条警告消息 MB rate (734400000) > level limit (16711680) 我没有修复。
  • 关于c++ - libav 生成具有极高帧速率的 MP4 文件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/70060148/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com