-1

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!

fidato
  • 719
  • 5
  • 22
  • I had jus created instance of File object of the file which I am selecting from the browser and checked the 'type' property of file instance. It is printing `video/mp4` in both the file cases. – fidato May 14 '15 at 08:02
  • post some code dude!! So that we can work on that!! – Guruprasad J Rao May 14 '15 at 08:45
  • @GuruprasadRao: Posted !! I think you shall get better idea. – fidato May 14 '15 at 09:48
  • are you using any plugin?? where you write this `loadFile`?? – Guruprasad J Rao May 14 '15 at 09:57
  • I am simply writing this method inside one js file and the method will called after you browse any file and file has been loaded within browser. Then I am simply printing out type of the `file` instance. which gives me `video/mp4` for the file which only consists of audio content. I believe that it should return 'audio/mp4' if the file consists of only audio content. – fidato May 14 '15 at 10:03
  • Something like **[this](http://jsfiddle.net/Guruprasad_Rao/z82q1xj5/1/)** – Guruprasad J Rao May 14 '15 at 10:28
  • Exactly the same thing, I gave url for download both the files, When you upload audio file, you will get `video/mp4` as a result. – fidato May 14 '15 at 10:37

2 Answers2

3

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

you can try

input.file.type.match('video.*')

It is described in detail here https://stackoverflow.com/a/7412549/3327294

Community
  • 1
  • 1
Rado
  • 155
  • 12
  • How do I match the things, if I am not a desired type. I mean i am getting `video/mp4` for 1st file and `video/mp4` for 2nd file. I believe that it should return `audio/mp4` for 1st file. Makes sense? – fidato May 14 '15 at 10:14