国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

Node + FFmpeg 實現Canvas動畫導出視頻

weij / 3090人閱讀

摘要:動畫錄制與圖片流傳輸動畫的記錄與傳送是個異步過程,這里返回一個,等待后端處理完畢,收到回應后,即完成此異步過程。

導言

Canvas為前端提供了動畫展示的平臺,隨著現在視頻娛樂的流行,你是否想過把Canvas動畫導出視頻?目前純前端的視頻編碼轉換(例如WebM Encoder Whammy)還存在許多限制,較為成熟的方案是將每幀圖片傳給后端實現,由后端調用FFmpeg進行視頻轉碼。整體流程并不復雜,這篇文章將帶大家實現這個過程。

整體方案

由前端記錄Canvas動畫的每幀圖像,以base64字符串形式傳給后端

利用node fluent-ffmpeg模塊,調用FFmpeg將圖片合并成視頻,并將視頻存儲在server端,并返回相應下載url

前端通過請求得到視頻文件

前端部分 每幀圖片生成

圖片生成可以通過canvas原生接口toDataURL實現,最終返回base64形式的圖像數據。

generatePng () {
  ...
  var imgData = canvas.toDataURL("image/png");
  return imgData;
}
動畫錄制與圖片流傳輸

動畫的記錄與傳送是個異步過程,這里返回一個Promise,等待后端處理完畢,收到回應后,即完成此異步過程。

以下代碼將canvas每幀動畫信息存入一個圖片數組imgs中,將數組轉成字符串的形式傳給后端。注意這里contentType設置為“text/plain”。

generateVideo () {
  var that = this;
  return new Promise (
    function (resolve, reject) {
      var imgs = [];
      ...
      window.requestAnimationFrame(that.recordTick.bind(that, imgs, resolve, reject));
    }
  )
}
recordTick (imgs, resolve, reject) {
  ...//每幀動畫的記錄信息,如時間戳等

  if (...) {//動畫終止條件
    this.stopPlay();
    imgs.push(this.generatePng());
    $.ajax({
      url: "/video/record",
      data: imgs.join(" "),
      method: "POST",
      contentType: "text/plain",
      success: function (data, textStatus, jqXHR) {
        resolve(data);
      },
      error: function (jqXHR, textStatus, errorThrown) {
        reject(errorThrown);
      }
    });
  } else {
    ...//每幀動畫展示的代碼

    imgs.push(this.generatePng());
    window.requestAnimationFrame(this.recordTick.bind(this, imgs, resolve, reject));
  }
}
視頻下載

上一節代碼中,動畫停止時,會通過post請求給后端傳送所有圖片數據,后端處理完畢后,返回數據中包含一個url,此url即為視頻文件的下載地址。

為了支持瀏覽器端用戶點擊下載,我們需要用到a標簽的download屬性,此屬性可以支持點擊a標簽后下載指定文件。

editor.generateVideo().then(function (data) {
  videoRecordingModal.setDownloadLink(data.url, data.filename);
  videoRecordingModal.changeStatus("recorded");
});
setDownloadLink: function (url, filename) {
  this.config.$dom.find(".video-download").attr("href", url);
  this.config.$dom.find(".video-download").attr("download", filename);
}
后端部分 圖片序列生成

接收到前端傳送的圖片數據后,我們首先需要將圖片解析、存儲在服務器中,我們建立以當前時間戳命名的文件夾,將圖片序列以一定格式存儲于其中。由于每張圖片寫入都是異步過程,為確保所有圖片都已處理完畢后,才執行視頻轉碼過程,我們需要用到Promise.all。

Promise.all(imgs.map(function (value, index) {
  var img = decodeBase64Image(value)
  var data = img.data
  var type = img.type
  return new Promise(function (resolve, reject) {
    fs.writeFile(path.resolve(__dirname, (folder + "/img" + index + "." + type)), data, "base64", function(err) {
      if (err) {
        reject(err)
      } else {
        resolve()
      }
    })
  })
})).then(function () {
  …//視頻轉碼
})

其中decodeBase64Image函數參考這里。

視頻生成

視頻生成利用FFmpeg轉碼工具。
首先確保server端安裝了FFmpeg

brew install ffmpeg

在項目中安裝fluent-ffmpeg,這是node調用ffmpeg的接口模塊

npm install fluent-ffmpeg --save

結合上一節圖片序列存儲的代碼,整個接口代碼如下:

app.post("/video/record", function(req, res) {
  var imgs = req.text.split(" ")
  var timeStamp = Date.now()
  var folder = "images/" + timeStamp
  if (!fs.existsSync(resolve(folder))){
    fs.mkdirSync(resolve(folder));
  }

  Promise.all(imgs.map(function (value, index) {
    var img = decodeBase64Image(value)
    var data = img.data
    var type = img.type
    return new Promise(function (resolve, reject) {
      fs.writeFile(path.resolve(__dirname, (folder + "/img" + index + "." + type)), data, "base64", function(err) {
        if (err) {
          reject(err)
        } else {
          resolve()
        }
      })
    })
  })).then(function () {
    var proc = new ffmpeg({ source: resolve(folder + "/img%d.png"), nolog: true })
      .withFps(25)
      .on("end", function() {
        res.status(200)
        res.send({
          url: "/video/mpeg/" + timeStamp,
          filename: "jianshi" + timeStamp + ".mpeg"
        })
      })
      .on("error", function(err) {
        console.log("ERR: " + err.message)
      })
      .saveToFile(resolve("video/jianshi" + timeStamp + ".mpeg"))
  })
})
視頻下載

最終將視頻文件傳輸給前端的接口代碼如下:

app.get("/video/mpeg/:timeStamp", function(req, res) {
  res.contentType("mpeg");
  var rstream = fs.createReadStream(resolve("video/jianshi" + req.params.timeStamp + ".mpeg"));
  rstream.pipe(res, {end: true});
})
效果預覽

注:此功能是個人項目”簡詩”的一部分,完整代碼可以查看https://github.com/moyuer1992...

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/82328.html

相關文章

  • 使用 canvas 實現精靈動畫

    摘要:文章首發于個人博客在最近項目中需要實現一個精靈動畫,素材方只提供了一個短視頻素材,所以在實現精靈動畫之前先介紹兩個工具來幫助我們更好的實現需求。 文章首發于個人博客:http://heavenru.com 在最近項目中需要實現一個精靈動畫,素材方只提供了一個短視頻素材,所以在實現精靈動畫之前先介紹兩個工具來幫助我們更好的實現需求。在這篇文章中,主要是介紹兩個命令行工具來實現將一個短視頻...

    岳光 評論0 收藏0
  • 使用 canvas 實現精靈動畫

    摘要:文章首發于個人博客在最近項目中需要實現一個精靈動畫,素材方只提供了一個短視頻素材,所以在實現精靈動畫之前先介紹兩個工具來幫助我們更好的實現需求。 文章首發于個人博客:http://heavenru.com 在最近項目中需要實現一個精靈動畫,素材方只提供了一個短視頻素材,所以在實現精靈動畫之前先介紹兩個工具來幫助我們更好的實現需求。在這篇文章中,主要是介紹兩個命令行工具來實現將一個短視頻...

    lastSeries 評論0 收藏0
  • 使用 canvas 實現精靈動畫

    摘要:文章首發于個人博客在最近項目中需要實現一個精靈動畫,素材方只提供了一個短視頻素材,所以在實現精靈動畫之前先介紹兩個工具來幫助我們更好的實現需求。 文章首發于個人博客:http://heavenru.com 在最近項目中需要實現一個精靈動畫,素材方只提供了一個短視頻素材,所以在實現精靈動畫之前先介紹兩個工具來幫助我們更好的實現需求。在這篇文章中,主要是介紹兩個命令行工具來實現將一個短視頻...

    call_me_R 評論0 收藏0
  • 慶祝新年?畫一顆圣誕樹?還是...

    摘要:關于節日圣誕節,元旦,看大家情侶在朋友圈里發各種慶祝的或者祝福的話語,甚是感動,然后悄悄拉黑了。預覽效果本地下打開很卡,火狐正常圣誕樹早先的時候是圣誕節的時候,看到各種用字符組成圣誕樹的形式,于是自己就去試了下,還是比較簡單的。 關于節日 圣誕節,元旦,看大家(情侶)在朋友圈里發各種慶祝的或者祝福的話語,甚是感動,然后悄悄拉黑了。作為單身狗,我們也有自己慶祝節日的方式,今天我們就來實現...

    cloud 評論0 收藏0

發表評論

0條評論

weij

|高級講師

TA的文章

閱讀更多
最新活動
閱讀需要支付1元查看
<