Lambda nodejs - 不支持带有 libcurl 字节范围的 mediainfo

Posted

技术标签:

【中文标题】Lambda nodejs - 不支持带有 libcurl 字节范围的 mediainfo【英文标题】:Lambda nodejs - mediainfo w/ libcurl byte range not supported 【发布时间】:2018-03-02 04:35:50 【问题描述】:

我创建了一个 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 + "'");
      
    
  );
;

【问题讨论】:

S3 确实支持范围请求...但是对于像 target 这样的预签名 URL,范围请求可能仅适用于专门编码为包含范围标头的预签名 URL。预签名 URL 是使用 Signature V2 还是 V4? V2 有AWSAccessKeyId=... 而V4 有X-Amz-Credential=... @Michael-sqlbot 看来它正在使用V2。正在生成的预签名 URL 具有以下查询参数:AWSAccessKeyId、Expires、Signature、x-amz-security-token 我尝试将 Range 添加到我的 getSignedUrl 参数中,但仍然遇到相同的问题 - 较小的文件有效,较大的文件无效。参数现在是... Bucket: bucket, Key: srcKey, Expires: 900, Range: 'bytes=0-100000' 嗯,这很有趣,因为如果有什么可以让它工作的话,它就是 V2,它通常是非常宽松的,需要在请求中添加额外的标头。您可以在存储桶中启用日志记录并查看失败的请求。 这似乎是 Mediainfo 的问题。我继续使用 ffprobe 来提取元数据,并且能够解决这个问题。感谢您的帮助@Michael-sqlbot 【参考方案1】:

我在使用 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);
  )

【讨论】:

以上是关于Lambda nodejs - 不支持带有 libcurl 字节范围的 mediainfo的主要内容,如果未能解决你的问题,请参考以下文章

如何修复不再支持 AWS Lambda nodejs8.10 错误

带有 Android SDK 的 intellij:-source 1.7 中不支持 lambda 表达式

获取 API Gateway 传递的 Lambda (Nodejs) 中的 url 参数

使用带有 ViewPager 错误的 GridView 创建的应用程序:-source 1.7 中不支持 lambda 表达式(使用 -source 8 或更高版本 [重复]

如何使用依赖项创建AWS nodejs lambda函数

AWS Lambda NodeJS 运行时是不是安装了 python?