我创建了一个lambda函数,使用ffmpeg和mediainfo从mp4视频文件创建缩略图,这对较小的文件非常有用。
到目前为止,我已经成功地为大小分别为372.5 KB和73.4 KB的文件创建了缩略图,但对于大小分别为2.9 MB和7.9 MB的文件,我收到了一个错误。
在我的cloudwatch日志中,我看到以下错误:

https://s3-us-west-2.amazonaws.com/object-path, HTTP server doesn't seem to support byte ranges. Cannot resume.

当我试图用mediainfo提取视频元数据时发生错误-我在ec2环境中用libcurl安装了mediainfo二进制文件。
我对curl、mediainfo和lambda都比较熟悉,所以我觉得我已经达到了自己的极限。我不确定这个特殊的错误是由lambda节点环境引起的,还是与mediainfo有关。
如果能帮助解决这个问题,我们将不胜感激。如果需要的话,我可以提供更清晰的信息。
参考代码--
process.env.PATH = process.env.PATH + ":/tmp/";
var child_process = require("child_process");
child_process.exec(
  "cp /var/task/ffmpeg /tmp/.; chmod 755 /tmp/ffmpeg;",
  function (error, stdout, stderr) {
    if (error) {
      console.log(error);
    }
  }
);

var mediainfo = require("mediainfo-wrapper");
var async = require("async");
var AWS = require("aws-sdk");
var fs = require("fs");
var utils = {
  decodeKey: function(key) {
    return decodeURIComponent(key).replace(/\+/g, " ");
  }
};
var s3 = new AWS.S3();
var thumbKeyPrefix = "thumbnails/",
  thumbWidth = 300,
  thumbHeight = 300,
  allowedFileTypes = ["mp4"];

exports.handler = function(event, context) {
  var tmpFile = fs.createWriteStream("/tmp/screenshot.jpg");
  var srcKey = utils.decodeKey(event.Records[0].s3.object.key),
    bucket = event.Records[0].s3.bucket.name,
    dstKey = thumbKeyPrefix + srcKey.replace(/\.\w+$/, ".jpg"),
    fileType = srcKey.match(/\.\w+$/),
    target = s3.getSignedUrl("getObject",{Bucket:bucket, Key:srcKey, Expires: 900}),
    metadata = {width: 0, height: 0, duration: 0};

  if(srcKey.indexOf(thumbKeyPrefix) === 0) return;
  if (fileType === null) {
    context.fail("Invalid filetype found for key: " + srcKey);
    return;
  }

  fileType = fileType[0].substr(1);

  if (allowedFileTypes.indexOf(fileType) === -1) {
    context.fail("Filetype " + fileType + " not valid for thumbnail, exiting");
    return;
  }

  async.waterfall([
    function createMetaData(next) {
      console.log('creating metadata...');
      mediainfo(target).then(function(data) {
        metadata.width = data[0].video[0].width[0] * 1;
        metadata.height = data[0].video[0].height[0] * 1;
        metadata.duration = data[0].video[0].duration[0] * 1;
        next(null);
      }).catch(function(err) {console.error(err)}); // ERROR LOGGED HERE
    },

    function createThumbnail(next) {
      console.log("creating thumbnail...");
      // use ffmpeg and metadata to create thumbnail
      // compute formattedTime, width, height ... cut for brevity

      var ffmpeg = child_process.spawn("ffmpeg", [
        "-ss", formattedTime, // time to take screenshot
        "-i", target, // url to stream from
        "-vf", "thumbnail,scale="+width+":"+height,
        "-q:v", "2",
        "-vframes", "1",
        "-f", "image2",
        "-c:v", "mjpeg",
        "pipe:1"
      ]);
      ffmpeg.on("error", function(err) {
        console.log(err);
      })
      ffmpeg.on("close", function(code) {
        if (code !== 0 ) {
          console.log("child process exited with code " + code);
        } else {
          console.log("Processing finished! Code: ", code);
        }
        tmpFile.end();
        next(code);
      });
      tmpFile.on("error", function(err) {
        console.log("stream err: ", err);
      });
      ffmpeg.on("end", function() {
        tmpFile.end();
      });
      ffmpeg.stdout.pipe(tmpFile)
        .on("error", function(err) {
          console.log("error while writing: ", err);
        });
    },

    function uploadThumbnail(next) {
      var tmpFile =  fs.createReadStream("/tmp/screenshot.jpg");
      child_process.exec("echo `ls -l -R /tmp`",
        function (error, stdout, stderr) {
          console.log("upload stdout: " + stdout)
      });
      var params = {
        Bucket: bucket,
        Key: dstKey,
        Body: tmpFile,
        ContentType: "image/jpg",
        ACL: "public-read",
        Metadata: {
          thumbnail: "TRUE"
        }
      };

      var uploadMe = s3.upload(params);
      uploadMe.send(
        function(err, data) {
          if (err != null) console.log("error: " +err);
            next(err);
          }
        );
      }
    ],
    function(err) {
      if (err) {
        console.error("Unable to generate thumbnail for '" + bucket + "/" + srcKey + "'" + " due to error: " + err);
        context.fail(err);
      } else {
        context.succeed("Created thumbnail for '" + bucket + "/" + srcKey + "'");
      }
    }
  );
};

最佳答案

在使用mediainfo时,我无法修复此问题。我转而使用ffprobe来提取所需的视频元数据,我将其简化为只使用视频持续时间…

function createMetaData(next) {
  console.log('capturing video duration...');
  var ffprobe = child_process.spawn('ffprobe', [
    '-v', 'quiet',
    '-print_format', 'json',
    '-show_format',
    target
  ]);
  ffprobe.stdout.on('data', function(data) {
    output.push(data);
  });
  ffprobe.on('error', function(err) {
    console.log('ffprobe error: ', err);
  });
  ffprobe.on('close', function() {
    var outputStr = output.join('');
    var jsonOut = {};
    jsonOut = JSON.parse(outputStr);
    videoDuration = jsonOut.format && jsonOut.format.duration ? jsonOut.format.duration : 0.5;
    next(null);
  })
}

关于node.js - Lambda Node.js-不支持带libcurl字节范围的mediainfo,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/46333518/

10-11 14:10