last_pts&gt current_pts使用ffmpeg libs(C ++) [英] What to do when last_pts > current_pts using ffmpeg libs (C++)

查看:227
本文介绍了last_pts&gt current_pts使用ffmpeg libs(C ++)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一些困难的时间弄清楚在哪里可以找到这个..



我建立一个简单的录音机来了解这个视频压缩领域,我面临一些奇怪的行为..



所有我需要解释的场景...



它非常简单...每一次我调用av_read_frame(input_context,input_packet)将pts保存到last_pts变量...



所以...



令我困扰的是,大约10%的我对av_read_frame的调用我得到
input_packet.pts> last_pts



导致错误消息编码器当我试图做...
记住它,我决定放下这些框架,当它发生....



我认为这不是一个好主意,只是放下框架,因为如果我得到它,它需要某种方式...



所以...当last_pts> current_pts时该怎么办? / p>

我将粘贴我的测试代码,Im使用从网络摄像头捕获视频a使用libx264编码器保存到mp4文件

  #include  
externC{
#include #include< libavformat / avformat.h>
#include< libswscale / swscale.h>
#include< libavutil / avutil.h>
#include< libavdevice / avdevice.h>
}

#include< QTime>
#include< QThread>
#include< QDebug>

#define SM_DEBUG

static const double max_fps = 30;
static const double min_loop_duration = 1000 / max_fps;
static const double max_duration = 5; // in seconds

static void sleep_if_needed(const int& elapsed){
int sleep_duration = min_loop_duration - elapsed;

if(sleep_duration> 0){
QThread :: msleep(sleep_duration);
}
}

#ifdef SM_DEBUG
static void log_packet(const AVPacket * pkt,
const AVRational& time_base,
int is_input = 0)
{

qDebug()<< ((is_input)?QString(>>):QString(<))< Size:<< QString :: number(pkt-> size)<<
pts:<< QString :: number(pkt-> pts)<<
pts_time:<< QString :: number(av_q2d(time_base)* pkt-> pts)<<
dts:<< QString :: number(pkt-> dts)<<
dts_time:<< QString :: number(av_q2d(time_base)* pkt-> dts);
}
#endif

int main()
{
int input_w,input_h,output_w = 640,output_h = 480;

av_register_all();
avdevice_register_all();
avcodec_register_all();
#ifdef SM_DEBUG
av_log_set_level(AV_LOG_DEBUG);
#else
av_log_set_level(AV_LOG_ERROR);
#endif

AVFormatContext * ic;
AVFormatContext * oc;

AVInputFormat * ifmt;

AVDictionary * opts = 0;

AVCodecContext * dec_ctx;
AVCodecContext * enc_ctx;
AVCodec * dec;
AVCodec * enc;

AVStream * ist;
AVStream * ost;

ifmt = av_find_input_format(v4l2);

av_dict_set(& opts,tune,zerolatency,AV_DICT_APPEND);
ic = avformat_alloc_context();

ic-> flags | = AVFMT_FLAG_NONBLOCK;

avformat_open_input(& ic,/ dev / video0,ifmt,& opts);

avformat_find_stream_info(ic,NULL);

av_dump_format(ic,0,ic-> filename,0);

AVFrame * frame;
AVFrame * tmp_frame;

ist = ic-> streams [0];

dec_ctx = ist-> codec;

input_w = dec_ctx-> width;
input_h = dec_ctx-> height;

dec_ctx-> flags | = CODEC_FLAG_LOW_DELAY;
dec = avcodec_find_decoder(dec_ctx-> codec_id);

av_format_set_video_codec(ic,dec);
avcodec_open2(dec_ctx,dec,NULL);

//输出

avformat_alloc_output_context2(& oc,NULL,MP4,/home/poste9/grava.mp4);

enc = avcodec_find_encoder(AV_CODEC_ID_H264);
ost = avformat_new_stream(oc,enc);
enc_ctx = ost-> codec;

enc_ctx-> codec_id = AV_CODEC_ID_H264;
enc_ctx-> width = output_w;
enc_ctx-> height = output_h;

ost-> time_base.num = ist-> time_base.num;
ost-> time_base.den = ist-> time_base.den;

enc_ctx-> time_base = ost-> time_base;

enc_ctx-> gop_size = 250;
enc_ctx-> keyint_min = 25;
enc_ctx-> qmax = 51;
enc_ctx-> qmin = 30;
enc_ctx-> pix_fmt = AV_PIX_FMT_YUV422P;
enc_ctx-> max_b_frames = 6;
enc_ctx-> flags | = CODEC_FLAG_GLOBAL_HEADER;
enc_ctx-> flags | = CODEC_FLAG_LOW_DELAY;

avcodec_open2(enc_ctx,enc,NULL);

avio_open2(& oc-> pb,oc-> filename,AVIO_FLAG_WRITE,
& oc-> interrupt_callback,NULL);

av_dump_format(oc,0,oc-> filename,1);

avformat_write_header(oc,NULL);

struct SwsContext * sws_ctx;

sws_ctx = sws_getContext(input_w,input_h,
dec_ctx-> pix_fmt,
output_w,output_h,enc_ctx-> pix_fmt,
SWS_BICUBIC,NULL,NULL,空值);

frame = av_frame_alloc();
tmp_frame = av_frame_alloc();

frame-> format = enc_ctx-> pix_fmt;
frame-> width = output_w;
frame-> height = output_h;
frame-> pts = AV_NOPTS_VALUE;

av_frame_get_buffer(frame,32);
av_frame_make_writable(frame);

int got_picture = 0;
int got_packet = 0;

double recording_duration = 0;

QTime定时器;

AVPacket pkt_out;

av_init_packet(& pkt_out);

timer.start();

bool started_recording = false;

int64_t start_time = 0;

int64_t last_pts = INT64_MIN;

while(1){
timer.restart();
AVPacket pkt_in;

av_read_frame(ic,& pkt_in);

if(pkt_in.size == 0){
sleep_if_needed(timer.elapsed());
继续;
}

avcodec_decode_video2(dec_ctx,tmp_frame,& got_picture,& pkt_in);

#ifdef SM_DEBUG
log_packet(& pkt_in,ist-> time_base,1);
#endif

如果(!started_recording){

start_time = pkt_in.dts;
started_recording = true;
}

if(pkt_in.pts< last_pts){

sleep_if_needed(timer.elapsed());

继续;
}

last_pts = pkt_in.pts;

frame-> pts =(pkt_in.dts - start_time);

if(!got_picture){

av_free_packet(& pkt_in);

sleep_if_needed(timer.elapsed());

继续;
} else {
sws_scale(sws_ctx,tmp_frame-> data,tmp_frame-> linesize,
0,input_h,frame-> data,frame-> linesize);

av_free_packet(& pkt_in);
}

av_init_packet(& pkt_out);

avcodec_encode_video2(enc_ctx,& pkt_out,frame,& got_packet);

if(got_packet){

if(pkt_out.pts< pkt_out.dts){
pkt_out.dts = pkt_out.pts;
}

pkt_out.stream_index = 0;

recording_duration = pkt_out.pts * av_q2d(ost-> time_base);
#ifdef SM_DEBUG
log_packet(& pkt_out,ost-> time_base,0);
#endif

av_interleaved_write_frame(oc,& pkt_out);

av_free_packet(& pkt_out);
}

if(recording_duration> = max_duration){

break;

} else {

sleep_if_needed(timer.elapsed());
}
}

av_write_trailer(oc);

av_dict_free(& opts);

av_frame_free(& frame);
av_frame_free(& tmp_frame);

sws_freeContext(sws_ctx);

avcodec_close(dec_ctx);
avcodec_close(enc_ctx);

avio_close(oc-> pb);
avformat_free_context(oc);

avformat_close_input(& ic);

return 0;
}


解决方案

这些框架是B框架。 B帧以解码顺序保存到流中,而不是呈现顺序。如果你看DTS,那么它可能会很好看。解码器的工作是在解码之后将帧重新排列成呈现顺序。



编辑。修复你的代码,从解码的帧中使用PTS,而不是数据包。


Im having some hard time figuring out where to find about this..

Im building a simple recorder to learn about this video compression universe and Im facing some weird behaviors..

Before all I need to explain the scenario...

Its very simple... everytime I call av_read_frame( input_context, input_packet ) I save the pts into the last_pts variable...

So...

Whats bothering me is the fact that about 10% of my calls to av_read_frame I get input_packet.pts > last_pts

Resulting in a error message from the encoder when I try to do it... Having it in mind I decided to just drop those frames when it happens....

I think it is not a good idea to just drop frames because if I get them, its needed somehow...

So... what to do when last_pts > current_pts ?

I will paste my test code that Im using capturing the video from webcam and saving to mp4 file with libx264 encoder

#include <QCoreApplication>

extern "C" {
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libswscale/swscale.h>
#include <libavutil/avutil.h>
#include <libavdevice/avdevice.h>
}

#include <QTime>
#include <QThread>
#include <QDebug>

#define SM_DEBUG

static const double max_fps = 30;
static const double min_loop_duration = 1000 / max_fps;
static const double max_duration = 5; // in seconds

static void sleep_if_needed(const int &elapsed) {
    int sleep_duration = min_loop_duration - elapsed;

    if (sleep_duration > 0)  {
        QThread::msleep(sleep_duration);
    }
}

#ifdef SM_DEBUG
static void log_packet(const AVPacket *pkt,
                       const AVRational &time_base,
                       int is_input=0)
{

    qDebug() << ((is_input) ? QString(">>") : QString("<<"))  << "Size:" << QString::number(pkt->size) <<
        "pts:" << QString::number(pkt->pts) <<
        "pts_time:" << QString::number(av_q2d(time_base) * pkt->pts) <<
        "dts:" << QString::number(pkt->dts) <<
        "dts_time:" << QString::number(av_q2d(time_base) * pkt->dts);
}
#endif

int main()
{
    int input_w, input_h, output_w = 640, output_h = 480;

    av_register_all();
    avdevice_register_all();
    avcodec_register_all();
#ifdef SM_DEBUG
    av_log_set_level(AV_LOG_DEBUG);
#else
    av_log_set_level(AV_LOG_ERROR);
#endif

    AVFormatContext *ic;
    AVFormatContext *oc;

    AVInputFormat *ifmt;

    AVDictionary *opts = 0;

    AVCodecContext* dec_ctx;
    AVCodecContext* enc_ctx;
    AVCodec *dec;
    AVCodec *enc;

    AVStream* ist;
    AVStream* ost;

    ifmt = av_find_input_format("v4l2");

    av_dict_set(&opts, "tune", "zerolatency", AV_DICT_APPEND);
    ic = avformat_alloc_context();

    ic->flags |= AVFMT_FLAG_NONBLOCK;

    avformat_open_input(&ic, "/dev/video0", ifmt, &opts);

    avformat_find_stream_info(ic, NULL);

    av_dump_format(ic, 0, ic->filename, 0);

    AVFrame *frame;
    AVFrame *tmp_frame;

    ist = ic->streams[0];

    dec_ctx =  ist->codec;

    input_w = dec_ctx->width;
    input_h = dec_ctx->height;

    dec_ctx->flags |= CODEC_FLAG_LOW_DELAY;
    dec = avcodec_find_decoder(dec_ctx->codec_id);

    av_format_set_video_codec(ic, dec);
    avcodec_open2(dec_ctx, dec, NULL);

    // output

    avformat_alloc_output_context2(&oc, NULL, "MP4", "/home/poste9/grava.mp4");

    enc = avcodec_find_encoder(AV_CODEC_ID_H264);
    ost = avformat_new_stream(oc, enc);
    enc_ctx = ost->codec;

    enc_ctx->codec_id = AV_CODEC_ID_H264;
    enc_ctx->width = output_w;
    enc_ctx->height = output_h;

    ost->time_base.num = ist->time_base.num;
    ost->time_base.den = ist->time_base.den;

    enc_ctx->time_base = ost->time_base;

    enc_ctx->gop_size = 250;
    enc_ctx->keyint_min = 25;
    enc_ctx->qmax = 51;
    enc_ctx->qmin = 30;
    enc_ctx->pix_fmt = AV_PIX_FMT_YUV422P;
    enc_ctx->max_b_frames = 6;
    enc_ctx->flags |= CODEC_FLAG_GLOBAL_HEADER;
    enc_ctx->flags |= CODEC_FLAG_LOW_DELAY;

    avcodec_open2(enc_ctx, enc, NULL);

    avio_open2(&oc->pb, oc->filename, AVIO_FLAG_WRITE,
               &oc->interrupt_callback, NULL);

    av_dump_format(oc, 0, oc->filename, 1);

    avformat_write_header(oc, NULL);

    struct SwsContext *sws_ctx;

    sws_ctx = sws_getContext(input_w, input_h,
                             dec_ctx->pix_fmt,
                             output_w, output_h, enc_ctx->pix_fmt,
                             SWS_BICUBIC, NULL, NULL, NULL);

    frame = av_frame_alloc();
    tmp_frame = av_frame_alloc();

    frame->format = enc_ctx->pix_fmt;
    frame->width = output_w;
    frame->height = output_h;
    frame->pts = AV_NOPTS_VALUE;

    av_frame_get_buffer(frame, 32);
    av_frame_make_writable(frame);

    int got_picture=0;
    int got_packet=0;

    double recording_duration = 0;

    QTime timer;

    AVPacket pkt_out;

    av_init_packet(&pkt_out);

    timer.start();

    bool started_recording = false;

    int64_t start_time = 0;

    int64_t last_pts = INT64_MIN;

    while(1) {
        timer.restart();
        AVPacket pkt_in;

        av_read_frame(ic, &pkt_in);

        if (pkt_in.size == 0) {
            sleep_if_needed(timer.elapsed());
            continue;
        }

        avcodec_decode_video2(dec_ctx, tmp_frame, &got_picture, &pkt_in);

#ifdef SM_DEBUG
        log_packet(&pkt_in, ist->time_base, 1);
#endif

        if (!started_recording) {

            start_time = pkt_in.dts;
            started_recording = true;
        }

        if (pkt_in.pts < last_pts) {

            sleep_if_needed(timer.elapsed());

            continue;
        }

        last_pts = pkt_in.pts;

        frame->pts = (pkt_in.dts - start_time);

        if (!got_picture) {

            av_free_packet(&pkt_in);

            sleep_if_needed(timer.elapsed());

            continue;
        } else {
            sws_scale(sws_ctx, tmp_frame->data, tmp_frame->linesize,
              0, input_h, frame->data, frame->linesize);

            av_free_packet(&pkt_in);
        }

        av_init_packet(&pkt_out);

        avcodec_encode_video2(enc_ctx, &pkt_out, frame, &got_packet);

        if (got_packet) {

            if (pkt_out.pts < pkt_out.dts) {
                pkt_out.dts = pkt_out.pts;
            }

            pkt_out.stream_index = 0;

            recording_duration = pkt_out.pts * av_q2d(ost->time_base);
#ifdef SM_DEBUG
            log_packet(&pkt_out, ost->time_base, 0);
#endif

            av_interleaved_write_frame(oc, &pkt_out);

            av_free_packet(&pkt_out);
        }

        if (recording_duration >= max_duration) {

            break;

        } else {

            sleep_if_needed(timer.elapsed());
        }
    }

    av_write_trailer(oc);

    av_dict_free(&opts);

    av_frame_free(&frame);
    av_frame_free(&tmp_frame);

    sws_freeContext(sws_ctx);

    avcodec_close(dec_ctx);
    avcodec_close(enc_ctx);

    avio_close(oc->pb);
    avformat_free_context(oc);

    avformat_close_input(&ic);

    return 0;
}

解决方案

These frames are B frames. B frames are saved to the stream in decoding order, not presentation order. If you look at the DTS it will probablly look ok. it is the job of the decoder to reorder frames into presentation order after they are decoded.

EDIT. to fix your code, use the PTS from the decoded frame, not the packet.

这篇关于last_pts&gt current_pts使用ffmpeg libs(C ++)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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