C++使用FFmpeg库实现图片转视频
生活随笔
收集整理的這篇文章主要介紹了
C++使用FFmpeg库实现图片转视频
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
這里的實現(xiàn)是使用ffmpeg4.1版本。
環(huán)境:Centos7.4
FFmpeg安裝目錄:/usr/local/ffmpeg
g++?版本:4.8.5
在ffmpeg4.1的版本中有一個轉封裝的示例代碼:remuxing.c,實現(xiàn)的是視頻文件的封裝轉換。
用這個示例修改,不斷讀取圖片文件,封裝到目標的視頻文件中。并設置相應的幀信息。
本文不涉及音視頻的編解碼,是直接將圖片從一種封裝格式文件中獲取出來然后打包成另外一種視頻文件封裝格式的文件。
/*** @file* libavformat/libavcodec demuxing and muxing API example.** Remux streams from one container format to another.* @example remuxing.c*/#include <libavutil/timestamp.h> #include <libavformat/avformat.h> // 自定義變量 const char* images[] = {"/opt/test/workdir/1_00001.png", "/opt/test/workdir/1_00002.png", "/opt/test/workdir/1_00003.png", "/opt/test/workdir/1_00004.png", "/opt/test/workdir/1_00005.png", "/opt/test/workdir/1_00006.png", "/opt/test/workdir/1_00007.png", "/opt/test/workdir/1_00008.png", "/opt/test/workdir/1_00009.png", "/opt/test/workdir/1_00010.png"};static void log_packet(const AVFormatContext *fmt_ctx, const AVPacket *pkt, const char *tag) {AVRational *time_base = &fmt_ctx->streams[pkt->stream_index]->time_base;printf("%s: pts:%s pts_time:%s dts:%s dts_time:%s duration:%s duration_time:%s stream_index:%d\n",tag,av_ts2str(pkt->pts), av_ts2timestr(pkt->pts, time_base),av_ts2str(pkt->dts), av_ts2timestr(pkt->dts, time_base),av_ts2str(pkt->duration), av_ts2timestr(pkt->duration, time_base),pkt->stream_index); }int main(int argc, char **argv) {// 輸出流格式結構體AVOutputFormat *ofmt = NULL;// 輸入輸出流處理上下文結構體AVFormatContext *ifmt_ctx = NULL;// 輸出流處理上下文結構體AVFormatContext *ofmt_ctx = NULL;// 包結構體AVPacket pkt;const char *in_filename, *out_filename;int ret, i;int stream_index = 0;int *stream_mapping = NULL;int stream_mapping_size = 0;// if (argc < 3) { // printf("usage: %s input output\n" // "API example program to remux a media file with libavformat and libavcodec.\n" // "The output format is guessed according to the file extension.\n" // "\n", argv[0]); // return 1; // }// in_filename = argv[1]; // out_filename = argv[2];out_filename = "/opt/test/workdir/test.avi";// 打開多媒體數據并且獲取一些信息,生成處理上下文結構體if ((ret = avformat_open_input(&ifmt_ctx, images[0], 0, 0)) < 0) {fprintf(stderr, "Could not open input file '%s'", images[0]);return -1;}// 主要是讀一些包(packets ),然后從中提取初流的信息, 把信息放在處理上下文中if ((ret = avformat_find_stream_info(ifmt_ctx, 0)) < 0) {fprintf(stderr, "Failed to retrieve input stream information");return -1;}// 打印關于輸入或輸出格式的詳細信息,例如持續(xù)時間,比特率,流,容器,程序,元數據,邊數據,編解碼器和時基// 最后一個參數 is_output 選擇指定的上下文是輸入(0)還是輸出(1),av_dump_format(ifmt_ctx, 0, images[0], 0);// 創(chuàng)建一個輸出媒體格式上下文avformat_alloc_output_context2(&ofmt_ctx, NULL, NULL, out_filename);if (!ofmt_ctx) {fprintf(stderr, "Could not create output context\n");ret = AVERROR_UNKNOWN;return -1;}// 視音頻流的個數stream_mapping_size = ifmt_ctx->nb_streams;stream_mapping = av_mallocz_array(stream_mapping_size, sizeof(*stream_mapping));if (!stream_mapping) {ret = AVERROR(ENOMEM);return -1;}// 獲取輸出流的格式結構ofmt = ofmt_ctx->oformat;for (i = 0; i < ifmt_ctx->nb_streams; i++) {AVStream *out_stream;AVStream *in_stream = ifmt_ctx->streams[i];// 設置解碼器參數AVCodecParameters *in_codecpar = in_stream->codecpar;if (in_codecpar->codec_type != AVMEDIA_TYPE_AUDIO &&in_codecpar->codec_type != AVMEDIA_TYPE_VIDEO &&in_codecpar->codec_type != AVMEDIA_TYPE_SUBTITLE) {stream_mapping[i] = -1;continue;}stream_mapping[i] = stream_index++;// 用輸出流上下文創(chuàng)建輸出流out_stream = avformat_new_stream(ofmt_ctx, NULL);if (!out_stream) {fprintf(stderr, "Failed allocating output stream\n");ret = AVERROR_UNKNOWN;return -1;}// 將解碼器參數復制給編碼器ret = avcodec_parameters_copy(out_stream->codecpar, in_codecpar);if (ret < 0) {fprintf(stderr, "Failed to copy codec parameters\n");return -1;}out_stream->codecpar->codec_tag = 0;out_stream->codecpar->bit_rate = 25;//out_stream->time_base = AVRational{1, 25};out_stream->time_base.den = 10;out_stream->time_base.num = 1;}// 打印關于輸入或輸出格式的詳細信息,例如持續(xù)時間,比特率,流,容器,程序,元數據,邊數據,編解碼器和時基// 最后一個參數 is_output 選擇指定的上下文是輸入(0)還是輸出(1),av_dump_format(ofmt_ctx, 0, out_filename, 1);// 打開或創(chuàng)建輸出文件if (!(ofmt->flags & AVFMT_NOFILE)) {ret = avio_open(&ofmt_ctx->pb, out_filename, AVIO_FLAG_WRITE);if (ret < 0) {fprintf(stderr, "Could not open output file '%s'", out_filename);return -1;}}// 輸出文件寫頭信息ret = avformat_write_header(ofmt_ctx, NULL);AVStream *out_stream = NULL;if (ret < 0) {fprintf(stderr, "Error occurred when opening output file\n");return -1;}for (i = 0; i < 10; i++) {// 重新創(chuàng)建輸入流if (i > 0) {// 打開多媒體數據并且獲取一些信息,生成處理上下文結構體if ((ret = avformat_open_input(&ifmt_ctx, images[i], 0, 0)) < 0) {fprintf(stderr, "Could not open input file '%s'", images[i]);return -1;}// 主要是讀一些包(packets ),然后從中提取初流的信息, 把信息放在處理上下文中if ((ret = avformat_find_stream_info(ifmt_ctx, 0)) < 0) {fprintf(stderr, "Failed to retrieve input stream information");return -1;}// 打印關于輸入或輸出格式的詳細信息,例如持續(xù)時間,比特率,流,容器,程序,元數據,邊數據,編解碼器和時基// 最后一個參數 is_output 選擇指定的上下文是輸入(0)還是輸出(1),av_dump_format(ifmt_ctx, 0, images[i], 0);}while (1) {// 定義輸入流和輸出流AVStream *in_stream = NULL;// 輸入流讀出幀包ret = av_read_frame(ifmt_ctx, &pkt);if (ret < 0)break;in_stream = ifmt_ctx->streams[pkt.stream_index];if (pkt.stream_index >= stream_mapping_size ||stream_mapping[pkt.stream_index] < 0) {av_packet_unref(&pkt);continue;}pkt.stream_index = stream_mapping[pkt.stream_index];if (out_stream == NULL) {out_stream = ofmt_ctx->streams[pkt.stream_index];}log_packet(ifmt_ctx, &pkt, "in");/* copy packet */pkt.pts = av_rescale_q_rnd(pkt.pts, in_stream->time_base, out_stream->time_base, AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX);pkt.dts = av_rescale_q_rnd(pkt.dts, in_stream->time_base, out_stream->time_base, AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX);pkt.duration = av_rescale_q(pkt.duration, in_stream->time_base, out_stream->time_base);pkt.pos = i;pkt.pts = i * 2; // 取值為time_base.num 和 time_base.den之前的一個值。log_packet(ofmt_ctx, &pkt, "out");// 輸出文件寫入幀包printf("pkt size: %d\n", pkt.size);ret = av_interleaved_write_frame(ofmt_ctx, &pkt);if (ret < 0) {fprintf(stderr, "Error muxing packet\n");break;}// 將幀包內容清除av_packet_unref(&pkt);}avformat_close_input(&ifmt_ctx);}// 寫入文件尾部署數據av_write_trailer(ofmt_ctx);// 關閉輸入流上下文avformat_close_input(&ifmt_ctx);/* close output */if (ofmt_ctx && !(ofmt->flags & AVFMT_NOFILE))avio_closep(&ofmt_ctx->pb);// 關閉輸出流上下文avformat_free_context(ofmt_ctx);av_freep(&stream_mapping);if (ret < 0 && ret != AVERROR_EOF) {fprintf(stderr, "Error occurred: %s\n", av_err2str(ret));return 1;}return 0; }編譯文件名:g++?c++文件名?-L/usr/local/ffmpeg/lib ?-lavcodec -lavdevice -lavfilter -lavformat -lavutil -lswscale ?-I/usr/local/ffmpeg/include
總結
以上是生活随笔為你收集整理的C++使用FFmpeg库实现图片转视频的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 情人节福利,恋爱话术微信小程序它来了(开
- 下一篇: 视频剪辑方法,在视频上添加图片或者视频