1

I am trying to read the metadata tags from an mp4 file into my javascript using the node module mp4js. I followed the model provided on that page but with some issue.

I tried the following:

var mp4 = require('mp4js');

mp4({ file: 'small.mp4', type: 'local' }, function (err, tags) {
    // tags now contains your MP4 tags
    console.log('Tags: ' + tags)
    $scope.mp4Tags = tags;
});

and I was met with Uncaught TypeError: Cannot read property 'join' of undefined

Does anyone know what I'm missing here? Could it be that the mp4 doesn't have any tags? I just googled "sample mp4" and downloaded something. It's my first time trying this module and I am pretty new to node.

I'm also open to other suggestions for reading mp4 metadata.

Thank you very much for your time and let me know if you need any additional from me.

EDIT 8.26.2015

Following Brad's suggestion, I tried the following code to read metadata from an mp4:

    var child_process = require('child_process');
ls = child_process.spawn('ffmpeg/bin/ffprobe.exe', ['-print_format', 'json', 'out.mp4']);

ls.stdout.on('data', function (data) {
    console.log('stdout: ' + data);
    $scope.mp4data = data;
});

I created mp4.out by following this example for adding a title meta tag using ffmpeg from the command line. Here is a screenshot of my output. Here is the command I entered:

ffmpeg -i in.avi -metadata title="my title" out.flv

After running my app with the code above, the value stored in $scope.mp4data is a Native Buffer that looks like this. All I see are some numbers, but no metadata tags. How can I view the metadata such as the title that I set using the command above? Am I missing something in the arguments? Or maybe I should be looking at something other than data?

Thanks for the help. I may just post this as a new question since the focus has shifted.

EDIT: Solution

Here's where I landed thanks to Brad's help:

$scope.mp4data = "";
ls.stdout.on('data', function (data) {
    $scope.mp4data = $scope.mp4data + data.toString();
});

ls.stdout.on('end', function (data) {
    $scope.mp4data = JSON.parse($scope.mp4data);
});

works great for reading metadata from my mp4! Thanks Brad!

user95227
  • 1,853
  • 2
  • 18
  • 36

1 Answers1

2

I recommend using FFprobe (from the FFmpeg project) to do this instead. It supports many containers, including MP4.

You can use ffprobe -print_format json to have it output JSON data that you can parse inside your Node.js app.

Some examples here: https://stackoverflow.com/a/8191228/362536

Community
  • 1
  • 1
Brad
  • 159,648
  • 54
  • 349
  • 530
  • Thanks for reaching out! Are FFmpeg commands entered into the command line? Is there a way to call something like `ffprobe -print_format json` from my javascript? – user95227 Aug 25 '15 at 18:00
  • @user95227 Yes, and yes. Just spawn a child process and read from its STDOUT stream until it ends. https://nodejs.org/api/child_process.html – Brad Aug 25 '15 at 18:18
  • sorry I just got back to this. Something like: `require('child_process').spawn()` `ls = spawn('ffprobe -print_format json', ['small.mp4']);` `ls.stdout.on('data', function (data) {` `console.log('stdout: ' + data);` `$scope.mp4data = data;` `});` – user95227 Aug 26 '15 at 12:58
  • @user95227 No, you need to put all parameters in the array of parameters, and you can't require and put that nowhere. `var child_process = require('child_process'); child_process.spawn('/path/to/ffprobe', ['-print_format', 'json', 'small.mp4']);` Something like that – Brad Aug 26 '15 at 13:00
  • Thanks for the quick reply! Ok I extracted the contents of the tar file that I downloaded from the FFmpeg site. So now I put the path in as `var child_process = require('child_process');` `child_process.spawn('ffmpeg-2.7.2/ffprobe.c', ['-print_format', 'json', 'small.mp4']);` . should the path be ending in a C file like that? Also, `child_process` is part of standard node.js and not something I need to use npm install on correct? – user95227 Aug 26 '15 at 13:20
  • @user95227 `child_process` is part of Node.js, yes. And no, you can't just execute arbitrary C code... you need to compile it. If you're using Linux, you can get a static build of FFmpeg with FFprobe here: http://ffmpeg.zeranoe.com/builds/ – Brad Aug 26 '15 at 13:21
  • Figured that wouldn't be possible. I'm on Windows. When I click the "Windows Builds" link on the ffmpeg site, it takes me to the same URL that you provided. Will those work for me as well? Thanks. EDIT: I have a ff-prompt.bat file and an ffprobe.xsd file in the presets folder after extracting the files downloaded from that URL – user95227 Aug 26 '15 at 13:29
  • Found the exe in there, I'll give it a shot. Thanks for your patience this is new to me – user95227 Aug 26 '15 at 13:38
  • I edited my question with my latest attempt. Please take a look if you get the chance. Thank you very much. – user95227 Aug 26 '15 at 14:26
  • @user95227 All you need to do is call `toString()` on that buffer. – Brad Aug 26 '15 at 16:28
  • I just get a [blank javascript object](http://i.imgur.com/DLG4clO.png) when I call `toString`. When I run `ffprobe -print_format json` in the command prompt, [I can see the metadata](http://i.imgur.com/bNRXrav.png) I really appreciate the help thus far and I've already learned a lot. Know what might be happening here? – user95227 Aug 26 '15 at 19:00
  • @user95227 Unfortunately, you're not actually getting information in your JSON metadata output, but your code is correct. You see the `{` and the `}` on your console, but the rest is STDERR debugging output. Try all the flags indicated in the example that I linked to earlier. `ffprobe -v quiet -print_format json -show_format -show_streams` – Brad Aug 26 '15 at 19:02
  • Thanks I see my content now when outputting it to the page via `

    mp4 Tags: {{mp4data}}

    `. [Here](http://i.imgur.com/dvYFvAX.png) is what it looks like. However though it seems silly to me, I'm struggling to reference these values in my javascript so that I can work with them. I've tried everything that looks like it would make sense, starting with `$scope.mp4data.streams` but the value comes up as undefined. It's the same when I [view in the debugger](http://i.imgur.com/7baViqV.png).
    – user95227 Aug 26 '15 at 19:41
  • @user95227 You have to parse the JSON. Keep concatenating to a buffer until `end` is fired on the stream, then use `JSON.parse()`. – Brad Aug 26 '15 at 19:59
  • Alright I will try that but may have to wait until tomorrow to let you know how it goes. Is `end` something that goes into `stdout.on` like `data`? `e.g. ls.stdout.on('end', function (data)` – user95227 Aug 26 '15 at 20:14
  • @user95227 Yes, `end` is a stream event. – Brad Aug 26 '15 at 20:14