QT开发用ffmpeg将图片制作成视频

继上一博文: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();
    //这个地方读取图片可以直接替换成其他内存,但是图片编码格式要一致,这里是yuv
 
  
     qDebug() << "------------------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);//释放输出视频相关数据结构
 
  
 
  
 
  
  
}

上面过程中的问题:

问题一:

  1. Using AVStream.codec to pass codec "  
  2.                    "parameters to muxers is deprecated, use AVStream.codecpar "  
  3.                    "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




你可能感兴趣的:(QT)