继上一博文:QT打开图片文件夹快速播放图片现在要将图片做成视频
1,第一种方式:cmd 的调用:因为什么都不懂,刚开始是想用命令行来做,在cmd下用命令能合成比较模糊的视频了
因输入文件的方式有两种调用方式:
第一种:ffmpeg -f image2 -pattern_type glob -framerate 24 -i 'IMG_*.JPG' ./IMG_.avi
第二种:ffmpeg -f image2 -r 1/5 -i img%03d.png -vcodec libx264 -pix_fmt yuv420p out.mp4
第二种方式要求输入图片文件名要有规则,如:%03d 代表 001 开始 如:%04d 代表 0001开始
我的文件的命名是 IMG_0152.JPG IMG_0220.JPG IMG_0288.JPG ...... 因此用第一种方式,第一种方式的输出文件名必是IMG_与文件名一样,而且不知为什么,当改成mp4时就生成不了视频了。
参考:http://ffmpeg.org/ffmpeg.html https://stackoverflow.com/questions/21586256/turning-images-into-videos-with-ffmpeg
接下来是在代码中调用了,最后不知什么原因运行不起来ffmpeg,不知哪里不对,真是小白,代码还是上来吧:
QString inputFiles = srcDir + "/IMG_0660.JPG";
QString outputFile = "/Users/ljx/IMG_.avi";
QString cmd = "ffmpeg";///usr/loacl/ffmpeg.app";
//QString cmd = "ffmpeg -f image2 -pattern_type glob -framerate 18 -i "+inputFiles + " " + outputFile;
qDebug() << "on_createAviBtn_clicked inputFiles:"<< inputFiles << " out:" < QStringList arguments;// //arguments.append("ffmpeg");// arguments.append("-f");// arguments.append("image2");// arguments.append("-pattern_type");// arguments.append("glob");// arguments.append("-framerate");// arguments.append("18");// arguments.append("-i");// arguments.append(inputFiles);// arguments.append(" ");// arguments.append(outputFile);arguments.append("-version");QProcess *p = new QProcess(this);int in = p->execute(cmd,arguments);//p.start(cmd,arguments);bool b = p->waitForStarted();bool b2 = p->waitForFinished();//等待完成QString strTemp=QString::fromLocal8Bit(p->readAllStandardOutput());qDebug() << "QProcess finished in: "<< in <<" b:"<< b + " b2:"<<< " strTemp:" << strTemp;
2. 第二种方式:用代码调用ffmpeg函数,下面这个终于能生成一个图片的视频了,有些参数还不太正,但原型出来了,相信再改动,就ok 了
void VideoMaker::makeVideo(QStringList srcList,QString desFile){if(srcList.size()<=0){return;}
qDebug() << "........-> makeVedio";av_register_all();//初始化解码器和复用器const char *out_filename = "/Users/ljx/maked.mp4";qDebug() << "-------------------AVFormatContext oc 1";AVFormatContext* oc = NULL;//其包含码流参数较多,是一个贯穿始终的数据结构,很多函数都要用到它作为参数//首先创建一个封装格式,avformat_alloc_output_context2(&oc, NULL, NULL,out_filename);//初始化一个用于输出的AVFormatContext结构体,视频帧率和宽高在此函数里面设置if(!oc){
qDebug() << "-------------------AVFormatContext oc init failed";return;}
oc->oformat->video_codec = AV_CODEC_ID_MJPEG;qDebug() << "-------------------AVStream st 2";AVStream *st;//构造一个输出流st = avformat_new_stream(oc, NULL);//初始化输出流if(!st){
av_free(oc);
qDebug() << "-------------------AVStream st init failed";return;}
qDebug() << "-------------------AVCodecContext c 3";AVCodecContext *c;av_dump_format(oc,0,out_filename,1);//一个打印的函数,应该没用c = st->codec;// c->codec_id = oc->oformat->video_codec;// c->codec_type = AVMEDIA_TYPE_VIDEO;// c->bit_rate = 400000;// c->width = 640;// c->height = 360;// c->time_base.den = 12;// c->time_base.num =1;// c->gop_size = 12;// c->pix_fmt = AV_PIX_FMT_YUV420P;// c->flags |= CODEC_FLAG_GLOBAL_HEADER;// c->codec_tag = 0;qDebug() << "-------------------AVCodec codec 4";AVCodec *codec;codec = avcodec_find_encoder(AV_CODEC_ID_MJPEG);//查找mjpeg解码器if (!codec){
av_free(oc);
qDebug() << "-------------------AVCodec codec init failed";return;}
qDebug() << "-------------------avcodec_get_context_defaults3 5";avcodec_get_context_defaults3(st->codec, codec);//申请AVStream->codec(AVCodecContext对象)空间并设置默认值(由avcodec_get_context_defaults3()设置//avcodec_get_context_defaults3(c,codec);avcodec_open2(c,codec,NULL);avcodec_parameters_from_context(st->codecpar,c);AVCodecParameters *codecpar = st->codecpar;codecpar->codec_type = AVMEDIA_TYPE_VIDEO;codecpar->bit_rate = 400000;//设置采样参数,即比特率codecpar->width = 640;//设置视频宽高,这里跟图片的宽高保存一致即可codecpar->height = 360;//codecpar->format = 12;st->time_base.den = 25;//设置帧率st->time_base.num = 1;st->codec->gop_size = 12;st->codec->pix_fmt = AV_PIX_FMT_YUV420P;//设置像素格式st->codec->codec_tag = 0;if (oc->oformat->flags & AVFMT_GLOBALHEADER)//一些格式需要视频流数据头分开{
qDebug() << "-------------------if (oc->oformat->flags & AVFMT_GLOBALHEADER) ";st->codec->flags |= CODEC_FLAG_GLOBAL_HEADER;}
if (!(oc->oformat->flags & AVFMT_NOFILE))//打开输出视频文件{
int ret = avio_open(&oc->pb, out_filename, AVIO_FLAG_WRITE);if (ret < 0) {av_free(oc);
printf("Could not open output file '%s'", out_filename);return;}
qDebug() << "-------------------if (!(oc->oformat->flags & AVFMT_NOFILE)) ";}
if (avformat_write_header(oc, NULL) < 0)//写文件头(Write file header){
printf("Error occurred when opening output file\n");return;}
qDebug() << "------------------open file 6";QFile file(srcList.at(0));if (!file.open(QIODevice::ReadOnly)){
printf("Error occurred when opening jpg file\n");return;}
QByteArray arr = file.readAll();//char* p = arr.data();uint8_t *mydata = (uint8_t*)arr.data();qDebug() << "-------------------arr.len:"<< arr.length() << " file.size:" << file.size() << " 1024 * 521:" << 1024*512;//QDataStream in(&file);//in.readBytes(mydata,file.size());//QTextStream in(&file);//打开一张jpeg图像并读取其数据,在这里图像最大为1M,如果超过1M,则需要修改1024*1024这里AVPacket *pkt = av_packet_alloc();qDebug() << "------------------av_interleaved_write_frame 7";pkt->data = mydata;pkt->size = file.size();//fclose(file);qDebug() << "------------------av_interleaved_write_frame 8";if (av_interleaved_write_frame(oc, pkt) < 0) //写入图像到视频{
printf("Error muxing packet\n");return;}
file.close();//这个地方读取图片可以直接替换成其他内存,但是图片编码格式要一致,这里是yuvqDebug() << "------------------free 9";av_free_packet(pkt);//释放掉帧数据包对象av_write_trailer(oc);//写文件尾(Write file trailer)delete mydata;//释放数据对象if (oc && !(oc->oformat->flags & AVFMT_NOFILE))avio_close(oc->pb);//关闭视频文件avformat_free_context(oc);//释放输出视频相关数据结构
}
上面过程中的问题:
问题一:
- Using AVStream.codec to pass codec "
- "parameters to muxers is deprecated, use AVStream.codecpar "
- "instead.
要设置codec_type
codecpar->codec_type = AVMEDIA_TYPE_VIDEO;参考:http://blog.csdn.net/yibu_refresh/article/details/52882925
问题二:读取图片成 uint8_t* : 原来char* 可以强制转成 uint8_t*
QFile file(“文件路径”);if (!file.open(QIODevice::ReadOnly)){
printf("Error occurred when opening jpg file\n");return;}
QByteArray arr = file.readAll();//char* p = arr.data();uint8_t *mydata = (uint8_t*)arr.data();
问题三: Could not find tag for codec none in stream #0, codec not currently supported in container” 在avcodec_open2 成功之后,利用avcodec_parameters_from_context将编码器的参数赋值给AVStream中的codecpar字段,问题解决
参考:http://blog.csdn.net/zhuquanfu/article/details/53786759
合成视频参考 http://www.zzzyk.com/show/7f3ead2a4a429116.htm
ffmpeg的c代码官方示例(在安装路径如:/usr/loacl/share/ffmpeg/examples下也有):
https://github.com/FFmpeg/FFmpeg/tree/master/doc/examples
QT程序发布:http://blog.csdn.net/liuyez123/article/details/50462637