6

I'm looking for a command that will read the metadata of a ‘*.mp4’ file and touch the file's timestamp with the creation time of the video. The command should be read-only with respect to the file contents, i.e. hashing the file before and after should yield the same result.

Situation: I made the mistake of moving pictures and videos from the internal storage of my phone to an SD card using Android's stock tool to do so (‘Settings’ → ‘Storage’ → ‘Transfer data to SD card’). Unfortunately, this bumped the timestamps of all of the files, and also messed around with directories other than DCIM/ (pictures and videos were also moved from the Download/, image/, Pictures/, and video/ directories). In hindsight it seems silly that I used such a tool (I'd normally use Ghost Commander), but it appeared as a notification when running low on space and it just looked so easy. I'm now trying to piece back together the timestamps of various pictures and videos.

I'm effectively looking for a video equivalent to the following command, which I used to sort out the images in DCIM/100ANDRO/:

exiv2 -T mv *.JPG

I skimmed through some FFmpeg documentation, but I see no mention of read-only commands or printing timestamps.

(Unfortunately for my situation, this approach does not offer a solution for files I didn't create, such as those in Download/, for which I want to appear in the media collection in chronological order of when I obtained them.)

8

Thanks to Warren for informing me about the mediainfo command in his partial answer.

I managed to construct a command that achieved the restoration of timestamps. It loops over the applicable files, and for each file, mediainfo reads the metadata, grep and sed select and format the timestamp, and touch applies it.

for file in *.mp4; do touch -t "$(mediainfo "$file" | grep -m 1 'Tagged date' | sed -r 's/.*([0-9]{4})-([0-9]{2})-([0-9]{2}) ([0-9]{2}):([0-9]{2}):([0-9]{2}).*/\1\2\3\4\5.\6/')" "$file"; done

The ‘select and format’ part could no doubt be a lot shorter/better; it looks cumbersome to me but I'm not fluent with regexs. Nevertheless, the command worked perfectly. I think I've quoted everything correctly, so it should work with any filename. It may not work if mediainfo outputs a different format but it's easily adaptable.

For example, here is a regex that correctly matches both the format of output from my *.mp4 files such as UTC 2013-11-15 11:36:06, and additionally the format of Warren's example of 2014-2-23T09:00:00Z from my.mov:

's/-/-0/g; s/.*([0-9]{4})-0?([0-9]{2})-0?([0-9]{2})[T ]([0-9]{2}):([0-9]{2}):([0-9]{2}).*/\1\2\3\4\5.\6/'

And apart from mediainfo which I actually had to install manually due to it not being in my distro's repositories (though it looks like newer releases now package it), it should be fairly portable and useful to others if they encounter a similar problem.

Note: Remember to check timezones. According to the GNU info pages, touch, date, and other GNU utilities use the TZ environment variable if set and the ‘system default rules’ otherwise. To see the timezone offset that'll be used, issue:

date +%:::z

To change it, set the TZ environment variable:

export TZ="UTC0"

If the video's timestamps are correct, and are correctly represented (i.e. the time value w.r.t. the timezone represents the correct point in time), then you should make sure that date +%:::z outputs the matching offset for the timestamp's timezone before running touch -t over those files (as above). Use stat to check the files, as it shows the time offset (like date +%:::z).

  • @Warren: Sorry! I've made a few too many tiny mistakes in critical places in the last few days! :-\ Probably a bit sleep deprived. Zz;-/ – James Haigh Feb 24 '14 at 11:46
2

You can use MediaInfo for that:

$ mediainfo my.mov | grep 'Recorded date'
Recorded date                            : 2014-2-23T09:00:00Z

Getting from that date format to a touch command should be a small matter of programming. Personally, I'd use Perl's Date::Manip module for this. It can almost cope with the above format; it requires 2-digit months with zero padding to understand this particular date format. Fixing that only requires a trivial regexp, which is of course easy in Perl.

$ perl -M'Date::Manip' -e 'print ParseDate("2014-02-23T09:00:00Z")'
2014022302:00:00

The fact that it prints shows that it's parsing. If you drop the 0, you'll see that it doesn't print anything, because ParseDate() returns undef.

  • Sorry about mistakenly writing *.MOV in my question. They were actually MOV_####.mp4 files and I mis-remembered the extension. Thank you for informing me about mediainfo, it was just the kind of tool I was looking for and I couldn't have solved this until I found such a tool. I have posted a complete solution. – James Haigh Feb 24 '14 at 10:22
  • Or to express it as a regex (seeing as I've been messing with them quite a bit on this problem), ‘MOV_[0-9]{4}\.mp4 files’! – James Haigh Feb 24 '14 at 10:30
  • Btw., did you have a ‘Tagged date’ field in your output? I didn't see a ‘Recorded date’ field in mine, so I wonder if ‘Tagged date’ would be more ubiquitous. I also had an ‘Encoded date’ field, but although they were identical in this instance, I chose ‘Tagged date’ because I assumed that tagging occurs after encoding so it would thus be closer to the modified time I was trying to restore if they were to be different. – James Haigh Feb 24 '14 at 10:53
  • My experience with this sort of problem is that your script may have to cope with many different date sources. MP4 — which actually derives from QuickTime, so the *.mov distinction probably doesn't matter — is complicated enough that there may be multiple ways to guess a recording date from any given file. Programmers being programmers, different video encoders are going to provide different sets of these fields. – Warren Young Feb 24 '14 at 11:35
  • Thankfully in my case, all of the videos that I'd created on my phone were recordings from the camera so had the same format. My downloaded videos aren't applicable to this method because I want to restore the time of download. (I know that Firefox has the timestamps stored within its application data, probably to beyond second precision, but I haven't yet managed to retrieve it.) Anyway, the reason I was asking was just to try to make my answer a bit more useful to others. – James Haigh Feb 24 '14 at 11:58
0

Follow James' advice above for MP4 and most QuickTime files. For AVI files, mediainfo will output Mastered date but the format is mostly un-parseable. Install ffmpeg to get ffprobe (also known as avprobe) then use:

for file in *.avi; do touch -t "$(ffprobe "$file" 2>&1 | grep -m 1 'creation_time' | sed -r 's/.*([0-9]{4})-([0-9]{2})-([0-9]{2}) ([0-9]{2}):([0-9]{2}):([0-9]{2}).*/\1\2\3\4\5.\6/')" "$file"; done

Note the mod before piping to grep. This is because ffprobe uses stderr not stdout.

0

exiftool:

exiftool "-CreateDate>FileModifyDate" FILES or FOLDERS

The name of the value you want may differ according to file format and other factors. Use below to print them:

exiftool -time:all -s FILE

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.