使用JavaScript获取“文件"对象的内容类型 [英] Get content type of 'File' object using javascript

查看:105
本文介绍了使用JavaScript获取“文件"对象的内容类型的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有两个具有相同扩展名的文件,如下所示:

1) test_audio_file.mp4 (仅包含音频内容)

2) test_video_file.mp4 (包括音频和视频内容)

上传文件后,我正在创建上传文件的File对象.

我想检查File对象的内容类型.即audio/mp4表示第一个文件,video/mp4表示第二个文件.

当我使用file_object.type方法打印文件类型时,在两种情况下都得到video/mp4.

我的假设是,第一个文件将得到audio/mp4,第二个文件将得到video/mp4.

我在这里放置一行代码:

loadFile: function(file) {
   console.log(file.type);
};

是否有任何方法或方法来获取第一个文件的内容类型audio和第二个文件的video.

任何想法都很棒.谢谢!

解决方案

浏览器通常会通过文件扩展名来假定为mime类型,在两种情况下均为mp4.

可以肯定的是,您可以检查文件的 binary 内容.

示例

假设您已将文件加载到ArrayBuffer中,则可以首先为其创建一个灵活的视图(不能使用Uint32Array,因为缓冲区的长度必须对齐4个字节,但文件并不总是这样,并且DataView会为您进行大端到小端的交换):

var view = new DataView(buffer);              // buffer = ArrayBuffer

(更新:删除了不需要"的第一个检查/使用的框大小,我建议在任何情况下都使用它.添加了更多详细信息.)

然后,检查 atom ( MP4文件格式使用原子"和框"而不是块"进行操作,就像许多其他类似格式一样)"ftyp"(0x66747970),字节4-8(大端):

if (view.getUint32(4) === 0x66747970) {       // = "ftyp"
    // ok, so far so good..
}

现在检查什么类型的MP4:

if (view.getUint32(8) === 0x64617368) {       // = "dash"
    // audio
}
else if (view.getUint32(8) === 0x6D703432) {  // = "mp42"
    // audio + video
}

我们现在可以为音频创建具有正确的mime-type设置的对象URL:

var blob = new Blob([buffer], {type: "audio/mp4"});
var url = URL.createObjectURL(blob);  // src for video/audio element

请注意,您还需要考虑其他许多类型(使用十六进制编辑器检查所需文件的实际值),并且可能需要将数组与indexOf()一起使用以检查多个可能的值:

var videoTypes = [0x6D703432, 0x69736F6D, ...];   // mp42, isom, ...
...
var type = view.getUint32(8);
if (videoTypes.indexOf(type) > -1) { /* ok! */ }

作为后备,您可以假设video/mp4用于未知的标头和类型,创建一个video/mp4作为mime-type的blob,然后让浏览器从那里处理文件.

有关偏移量和框长的详细信息,请参见上面的链接.

工作演示

以下演示仅限于检查给定示例文件的类型.当然,您将需要扩展其他MP4类型(类型字段)以使用诸如音频类型的一种数组,视频类型的一种数组等在实际应用中进行检入.

加载其中一个文件进行分析.

 var inp = document.querySelector("input");
inp.onchange = function(e) {
  var reader = new FileReader();
  reader.onload = analyze;
  reader.readAsArrayBuffer(e.target.files[0]);
};

function analyze(e) {
  var buffer = e.target.result, view = new DataView(buffer), blob, url;
  
  // check file type
  if (view.getUint32(4) !== 0x66747970) {                    // = "ftyp"
    alert("Not MP4 file!"); return
  }

  // check if audio or audio+video
  if (view.getUint32(8) === 0x64617368) {                    // = "dash"
    alert("Audio\n(See console for example url)");
    blob = new Blob([buffer], {type: "audio/mp4"});
  }
  else if (view.getUint32(8) === 0x6D703432 ||               // = "mp42"
           view.getUint32(8) === 0x69736F6D) {               // = "isom"
    alert("Video+Audio\n(See console for example url)");
    blob = new Blob([buffer], {type: "video/mp4"});
  }
  else {                                                    // assume video/mp4
    alert("Unsupported:\n0x" + (view.getUint32(8)).toString(16));
    blob = new Blob([buffer], {type: "video/mp4"});
  }
  
  // convert blob to an URL that can be used with a video/audio element
  url = (URL || webkitURL).createObjectURL(blob);
  console.log("Copy and paste this into a tab, wo/quotes:", url);
} 

 Pick a MP4 file: <input type="file"> 

I have two files with same extensions as follows:

1) test_audio_file.mp4 (Consist of only audio content)

2) test_video_file.mp4 (Consist of audio and video content)

After uploading a file, I am creating File object of uploaded file.

I want to check content type of the File object. i.e. audio/mp4 for first file and video/mp4 for second file.

When I print the file type using file_object.type method, I am getting video/mp4 in both the cases.

My assumption was I will get audio/mp4 for first file and video/mp4 for the second file.

I am putting a line of code here:

loadFile: function(file) {
   console.log(file.type);
};

Is there any method or way to get a content type audio for first file and video for second file.

Any ideas would be great. Thanks!

解决方案

The browser will assume a mime-type often by the file extension which in both cases here are mp4.

To be sure, you can check the binary content of the file.

Example

Assuming you have loaded the file in an ArrayBuffer you could first create a flexible view for it (Uint32Array cannot be used as the length of the buffer must be 4-bytes aligned which is not always the case for the file, and DataView will do big-endian to little-endian swapping for you):

var view = new DataView(buffer);              // buffer = ArrayBuffer

(Update: removed "unneeded" first check/used for box size which I recommend to use in any case. More details added.)

Then, check for the atom (the MP4 file-format operates with "atoms" and "boxes" instead of "chunks" as in many other similar formats) "ftyp" (0x66747970) in bytes 4-8 (big-endian):

if (view.getUint32(4) === 0x66747970) {       // = "ftyp"
    // ok, so far so good..
}

Now check what type of MP4 this is:

if (view.getUint32(8) === 0x64617368) {       // = "dash"
    // audio
}
else if (view.getUint32(8) === 0x6D703432) {  // = "mp42"
    // audio + video
}

We can now create an object-URL with the proper mime-type set, for audio:

var blob = new Blob([buffer], {type: "audio/mp4"});
var url = URL.createObjectURL(blob);  // src for video/audio element

Note that there are many other types that you need to consider (use a hex editor to inspect the actual values of the files you expect) and you will probably want to use arrays with indexOf() to check for multiple possible values:

var videoTypes = [0x6D703432, 0x69736F6D, ...];   // mp42, isom, ...
...
var type = view.getUint32(8);
if (videoTypes.indexOf(type) > -1) { /* ok! */ }

As a fallback you can assume video/mp4 for unknown headers and types, create a blob with video/mp4 as mime-type and let the browser deal with the file from there.

Also see link above for details on offsets and box lengths.

Working demo

The following demo is limited to check for the types of the given example files. You will of course need to extend for other MP4 types (type field) to check in the real-world application using for example one array for audio types, one for video etc.

Load one of the files to have it analyzed.

var inp = document.querySelector("input");
inp.onchange = function(e) {
  var reader = new FileReader();
  reader.onload = analyze;
  reader.readAsArrayBuffer(e.target.files[0]);
};

function analyze(e) {
  var buffer = e.target.result, view = new DataView(buffer), blob, url;
  
  // check file type
  if (view.getUint32(4) !== 0x66747970) {                    // = "ftyp"
    alert("Not MP4 file!"); return
  }

  // check if audio or audio+video
  if (view.getUint32(8) === 0x64617368) {                    // = "dash"
    alert("Audio\n(See console for example url)");
    blob = new Blob([buffer], {type: "audio/mp4"});
  }
  else if (view.getUint32(8) === 0x6D703432 ||               // = "mp42"
           view.getUint32(8) === 0x69736F6D) {               // = "isom"
    alert("Video+Audio\n(See console for example url)");
    blob = new Blob([buffer], {type: "video/mp4"});
  }
  else {                                                    // assume video/mp4
    alert("Unsupported:\n0x" + (view.getUint32(8)).toString(16));
    blob = new Blob([buffer], {type: "video/mp4"});
  }
  
  // convert blob to an URL that can be used with a video/audio element
  url = (URL || webkitURL).createObjectURL(blob);
  console.log("Copy and paste this into a tab, wo/quotes:", url);
}

Pick a MP4 file: <input type="file">

这篇关于使用JavaScript获取“文件"对象的内容类型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆