ffmpeg更改视频的帧率

avatar
作者
筋斗云
阅读量:0

note

视频帧率调整
    帧率(fps-frame per second)
    例如:原来帧率为30,调整后为1   现象:原来是每秒有30张图像,调整后每秒1张图像,看着图像很慢
    实现:在每秒的时间区间里,取一张图像

version

#define LIBAVFILTER_VERSION_MINOR 12

#define LIBAVFILTER_VERSION_MICRO 100

#define LIBAVCODEC_VERSION_MINOR 31

#define LIBAVCODEC_VERSION_MICRO 102

code

void CFfmpegOps::ChangeVideoFPS(const char *in_mp4, const char *out_mp4) {     AVFormatContext *in_fmt_ctx = nullptr;     const AVInputFormat *in_fmt = nullptr;     AVFormatContext *out_fmt_ctx = nullptr;     const AVOutputFormat *out_fmt = nullptr;     int ret = -1;     int video_stream_index = 0;     const AVCodec *decoder = nullptr;     AVCodecContext *decoder_ctx = nullptr;     const AVCodec* encoder = nullptr;     AVCodecContext* encoder_ctx = nullptr;     AVStream* in_avstream = nullptr;     AVStream* out_avstream = nullptr;     const AVFilter * avfilter_buffer_src = nullptr; // 源,video buffer可设置的参数有     AVFilterContext* avfilter_ctx_buffer_src = nullptr;     const AVFilter * avfilter_fps = nullptr;    // 中间节点,video fps可设置的参数包含fps     AVFilterContext* avfilter_ctx_fps = nullptr;     const AVFilter* avfilter_buffer_sink = nullptr; // 终,video buffersink可设置的参数只有pixel formats     AVFilterContext* avfilter_ctx_buffer_sink = nullptr;     AVFilterGraph* avfiltergraph = nullptr;     AVPacket* avpacket_src = nullptr;     AVFrame* avframe_src = nullptr;     AVFrame* avframe_dest = nullptr;     AVPacket* avpacket_dest = nullptr;     AVRational pixel_aspect = {.num = 1, .den = 1};      ret = avformat_open_input(&in_fmt_ctx, in_mp4, nullptr, nullptr);     if (ret < 0)     {         printf("avformat_open_input error(%s)\n", GetFfmpegERR(ret));         goto END;     }     in_fmt = in_fmt_ctx->iformat;      ret = avformat_find_stream_info(in_fmt_ctx, nullptr);     if (ret < 0)     {         printf("avformat_find_stream_info error(%s)\n", GetFfmpegERR(ret));         goto END;     }      ret = av_find_best_stream(in_fmt_ctx, AVMEDIA_TYPE_VIDEO, -1, -1, nullptr, 0);     if (ret < 0)     {         printf("av_find_best_stream error(%s)\n", GetFfmpegERR(ret));         goto END;     }     video_stream_index = ret;     in_avstream = in_fmt_ctx->streams[video_stream_index];      decoder = avcodec_find_decoder(in_avstream->codecpar->codec_id);     if (!decoder)     {         printf("avcodec_find_decoder error\n");         goto END;     }      decoder_ctx = avcodec_alloc_context3(decoder);     if (!decoder_ctx)     {         printf("avcodec_alloc_context3 error\n");         goto END;     }      ret = avcodec_parameters_to_context(decoder_ctx, in_avstream->codecpar);     if (ret < 0)     {         printf("avcodec_parameters_to_context error(%s)\n", GetFfmpegERR(ret));         goto END;     }      ret = avcodec_open2(decoder_ctx, decoder, nullptr);     if (ret < 0)     {         printf("avcodec_open2 error(%s)\n", GetFfmpegERR(ret));         goto END;     }      avfiltergraph = avfilter_graph_alloc();     if (!avfiltergraph)     {         printf("avfilter_graph_alloc error\n");         goto END;     }      avfilter_buffer_src = avfilter_get_by_name("buffer");   // buffer对应video,abuffer对应audio     if (!avfilter_buffer_src)     {         printf("avfilter_get_by_name error\n");         goto END;     }     printf("avfilter_buffer_src->desc:%s\n", avfilter_buffer_src->description);      avfilter_ctx_buffer_src = avfilter_graph_alloc_filter(avfiltergraph, avfilter_buffer_src, avfilter_buffer_src->name);     if (!avfilter_ctx_buffer_src)     {         printf("avfilter_graph_alloc_filter error\n");         goto END;     }      // 设置avfilter_ctx_buffer_src的可选参数     // 参照libavfilter/buffersrc.c文件中对video buffer的可选参数描述     ret = av_opt_set(avfilter_ctx_buffer_src,                  "width", std::to_string(in_avstream->codecpar->width).c_str(),                  AV_OPT_SEARCH_CHILDREN);     if (ret < 0)     {         printf("av_opt_set error(%s)\n", GetFfmpegERR(ret));         goto END;     }     ret = av_opt_set(avfilter_ctx_buffer_src,                  "height", std::to_string(in_avstream->codecpar->height).c_str(),                  AV_OPT_SEARCH_CHILDREN);     if (ret < 0)     {         printf("av_opt_set error(%s)\n", GetFfmpegERR(ret));         goto END;     }     ret = av_opt_set(avfilter_ctx_buffer_src,                  "pix_fmt", av_get_pix_fmt_name((AVPixelFormat)(in_avstream->codecpar->format)),                  AV_OPT_SEARCH_CHILDREN);     if (ret < 0)     {         printf("av_opt_set error(%s)\n", GetFfmpegERR(ret));         goto END;     }     ret = av_opt_set_q(avfilter_ctx_buffer_src,                 "time_base", in_avstream->time_base,                 AV_OPT_SEARCH_CHILDREN);     if (ret < 0)     {         printf("av_opt_set error(%s)\n", GetFfmpegERR(ret));         goto END;     }     ret = av_opt_set_q(avfilter_ctx_buffer_src,                 "frame_rate", in_avstream->r_frame_rate,                 AV_OPT_SEARCH_CHILDREN);     if (ret < 0)     {         printf("av_opt_set error(%s)\n", GetFfmpegERR(ret));         goto END;     }      ret = av_opt_set_q(avfilter_ctx_buffer_src,                     "pixel_aspect", pixel_aspect,                     AV_OPT_SEARCH_CHILDREN);     if (ret < 0)     {         printf("av_opt_set error(%s)\n", GetFfmpegERR(ret));         goto END;     }      // 上面已经设置过参数,初始化就不传参了     ret = avfilter_init_str(avfilter_ctx_buffer_src, nullptr);     if (ret < 0)     {         printf("avfilter_init_str error(%s)\n", GetFfmpegERR(ret));         goto END;     }      avfilter_fps = avfilter_get_by_name("fps");     if (!avfilter_fps)     {         printf("avfilter_get_by_name error\n");         goto END;     }     printf("avfilter_fps->desc:%s\n", avfilter_fps->description);      avfilter_ctx_fps = avfilter_graph_alloc_filter(avfiltergraph, avfilter_fps, avfilter_fps->name);     if (!avfilter_ctx_fps)     {         printf("avfilter_graph_alloc_filter error\n");         goto END;     }      ret = av_opt_set(avfilter_ctx_fps,                      "fps", "1",                     AV_OPT_SEARCH_CHILDREN);     if (ret < 0)     {         printf("av_opt_set error(%s)\n", GetFfmpegERR(ret));         goto END;     }          ret = avfilter_init_str(avfilter_ctx_fps, nullptr);     if (ret < 0)     {         printf("avfilter_init_str error(%s)\n", GetFfmpegERR(ret));         goto END;     }      avfilter_buffer_sink = avfilter_get_by_name("buffersink");     if (!avfilter_buffer_sink)     {         printf("avfilter_get_by_name error\n");         goto END;     }     printf("avfilter_buffer_sink->desc:%s\n", avfilter_buffer_sink->description);      avfilter_ctx_buffer_sink = avfilter_graph_alloc_filter(avfiltergraph, avfilter_buffer_sink, avfilter_buffer_sink->name);     if (!avfilter_ctx_buffer_sink)     {         printf("avfilter_graph_alloc_filter error\n");         goto END;     }      ret = avfilter_init_str(avfilter_ctx_buffer_sink, nullptr);     if (ret < 0)     {         printf("avfilter_init_str error(%s)\n", GetFfmpegERR(ret));         goto END;     }      // 把avfilter组成链     // avfilter_link的作用,在src和dest之间新建AVFilterLink实例     // srcpad:src的输出通道编号     // destpad:dest的输入通道编号     ret = avfilter_link(avfilter_ctx_buffer_src, 0, avfilter_ctx_fps, 0);     if (ret != 0)     {         printf("avfilter_link error(%s)\n", GetFfmpegERR(ret));         goto END;     }      ret = avfilter_link(avfilter_ctx_fps, 0, avfilter_ctx_buffer_sink, 0);     if (ret != 0)     {         printf("avfilter_link error(%s)\n", GetFfmpegERR(ret));         goto END;     }      ret = avfilter_graph_config(avfiltergraph, nullptr);     if (ret < 0)     {         printf("avfilter_graph_config error(%s)\n", GetFfmpegERR(ret));         goto END;     }      ret = avformat_alloc_output_context2(&out_fmt_ctx, nullptr, nullptr, out_mp4);     if (ret < 0)     {         printf("avformat_alloc_output_context2 error(%s)\n", GetFfmpegERR(ret));         goto END;     }     out_fmt = out_fmt_ctx->oformat;      encoder = avcodec_find_encoder(decoder->id);     if (!encoder)     {         printf("avcodec_find_encoder error\n");         goto END;     }      encoder_ctx = avcodec_alloc_context3(encoder);     if (!encoder_ctx)     {         printf("avcodec_alloc_context3 error\n");         goto END;     }     encoder_ctx->pix_fmt = (AVPixelFormat)(av_buffersink_get_format(avfilter_ctx_buffer_sink));     encoder_ctx->width = av_buffersink_get_w(avfilter_ctx_buffer_sink);     encoder_ctx->height = av_buffersink_get_h(avfilter_ctx_buffer_sink);     encoder_ctx->time_base = av_buffersink_get_time_base(avfilter_ctx_buffer_sink);     encoder_ctx->framerate = av_buffersink_get_frame_rate(avfilter_ctx_buffer_sink);     encoder_ctx->gop_size = decoder_ctx->gop_size;     encoder_ctx->max_b_frames = decoder_ctx->max_b_frames;      if (out_fmt->flags & AVFMT_GLOBALHEADER)     {         encoder_ctx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;     }      ret = avcodec_open2(encoder_ctx, encoder, nullptr);     if (ret < 0)     {         printf("avcodec_open2 error(%s)\n", GetFfmpegERR(ret));         goto END;     }      out_avstream = avformat_new_stream(out_fmt_ctx, encoder);     if (!out_avstream)     {         printf("avformat_new_stream error\n");         goto END;     }     out_avstream->time_base = av_buffersink_get_time_base(avfilter_ctx_buffer_sink);     out_avstream->r_frame_rate = av_buffersink_get_frame_rate(avfilter_ctx_buffer_sink);     out_avstream->avg_frame_rate = av_buffersink_get_frame_rate(avfilter_ctx_buffer_sink);      ret = avcodec_parameters_from_context(out_avstream->codecpar, encoder_ctx);     if (ret < 0)     {         printf("avcodec_parameters_from_context error(%s)\n", GetFfmpegERR(ret));         goto END;     }      ret = avio_open(&(out_fmt_ctx->pb), out_mp4, AVIO_FLAG_WRITE);     if (ret < 0)     {         printf("avio_open error(%s)\n", GetFfmpegERR(ret));         goto END;     }      // 调用avformat_write_header后,out_avstream的时间基发生了变化(10->102400),容器要求?     ret = avformat_write_header(out_fmt_ctx, nullptr);     if (ret < 0)     {         printf("avformat_write_header error(%s)\n", GetFfmpegERR(ret));         goto END;     }      avpacket_src = av_packet_alloc();     if (!avpacket_src)     {         printf("av_packet_alloc error\n");         goto END;     }      avpacket_dest = av_packet_alloc();     if (!avpacket_dest)     {         printf("av_packet_alloc error\n");         goto END;     }      avframe_src = av_frame_alloc();     if (!avframe_src)     {         printf("av_frame_alloc error\n");         goto END;     }      avframe_dest = av_frame_alloc();     if (!avframe_dest)     {         printf("av_frame_alloc error\n");         goto END;     }      while (1)     {         // 从输入文件读取压缩视频帧         ret = av_read_frame(in_fmt_ctx, avpacket_src);         if (ret < 0)         {             printf("av_read_frame error(%s)\n", GetFfmpegERR(ret));             break;         }          if (avpacket_src->stream_index != video_stream_index)         {             av_packet_unref(avpacket_src);             continue;         }          // 把压缩视频帧发送给解码器         ret = avcodec_send_packet(decoder_ctx, avpacket_src);         if (ret != 0)         {             printf("avcodec_send_packet error(%s)\n", GetFfmpegERR(ret));         }         else         {             // 接收解码器的输出视频帧             ret = avcodec_receive_frame(decoder_ctx, avframe_src);             if (ret != 0)             {                 printf("avcodec_receive_frame error(%s)\n", GetFfmpegERR(ret));             }             else             {                 // 把视频帧交给avfilter                 ret = av_buffersrc_write_frame(avfilter_ctx_buffer_src, avframe_src);                 if (ret != 0)                 {                     printf("av_buffersrc_write_frame error(%s)\n", GetFfmpegERR(ret));                 }                 else                 {                     // 从avfilter获取视频帧                     ret = av_buffersink_get_frame(avfilter_ctx_buffer_sink, avframe_dest);                     if (ret < 0)                     {                         printf("av_buffersink_get_frame error(%s)\n", GetFfmpegERR(ret));                     }                     else                     {                         // 把视频帧交给编码器                         ret = avcodec_send_frame(encoder_ctx, avframe_dest);                         if (ret != 0)                         {                             printf("avcodec_send_frame error(%s)\n", GetFfmpegERR(ret));                         }                         else                         {                             // 从编码器获取压缩视频帧                             ret = avcodec_receive_packet(encoder_ctx, avpacket_dest);                             if (ret != 0)                             {                                 printf("avcodec_receive_packet error(%s)\n", GetFfmpegERR(ret));                             }                             else                             {                                 av_packet_rescale_ts(avpacket_dest, encoder_ctx->time_base, out_avstream->time_base);                                  // 写入到输出文件                                 ret = av_write_frame(out_fmt_ctx, avpacket_dest);                                 if (ret < 0)                                 {                                     printf("av_write_frame error(%s)\n", GetFfmpegERR(ret));                                 }                             }                         }                     }                 }             }         }     }      ret = av_write_trailer(out_fmt_ctx);     if (ret < 0)     {         printf("av_write_trailer error(%s)\n", GetFfmpegERR(ret));         goto END;     }  END:     if (avframe_dest)     {         av_frame_free(&avframe_dest);         avframe_dest = nullptr;     }     if (avframe_src)     {         av_frame_free(&avframe_src);         avframe_src = nullptr;     }     if (avpacket_src)     {         av_packet_free(&avpacket_src);         avpacket_src = nullptr;     }     if (avpacket_dest)     {         av_packet_free(&avpacket_dest);         avpacket_dest = nullptr;     }     if (avfilter_ctx_buffer_sink)     {         avfilter_free(avfilter_ctx_buffer_sink);         avfilter_ctx_buffer_sink = nullptr;     }     if (avfilter_ctx_fps)     {         avfilter_free(avfilter_ctx_fps);         avfilter_ctx_fps = nullptr;     }     if (avfilter_ctx_buffer_src)     {         avfilter_free(avfilter_ctx_buffer_src);         avfilter_ctx_buffer_src = nullptr;     }     if (avfiltergraph)     {         avfilter_graph_free(&avfiltergraph);         avfiltergraph = nullptr;     }     if (encoder_ctx)     {         avcodec_free_context(&encoder_ctx);         encoder_ctx = nullptr;     }     if (decoder_ctx)     {         avcodec_free_context(&decoder_ctx);         decoder_ctx = nullptr;     }     if (out_fmt_ctx)     {         avformat_free_context(out_fmt_ctx);         out_fmt_ctx = nullptr;     }     if (in_fmt_ctx)     {         avformat_free_context(in_fmt_ctx);         in_fmt_ctx = nullptr;     } }

performance

广告一刻

为您即时展示最新活动产品广告消息,让您随时掌握产品活动新动态!