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.
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.
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">