What options are available to _losslessly_ trim mp4/m4v video in macOS?

iMovie (not lossless, but better than before)

iMovie v10 (released some time after the question was originally asked) now better handles more media types, so avoids the import re-encode for most H.264 (mp4, m4v, mov, AVHDC, mts, mt2s) content.

It will still, however, re-encode on export so cannot be technically lossless—another new feature, however, is the ability to customise the export quality, which can be closer-to-lossless. I suspect this part of the answer can apply equally to other 'project driven' video editing software (e.g. Premiere or Final Cut) because I think they all generally re-encode on output, though are usually very easy to use for precise trimming.

Personally, I generally think a single re-encode isn't a huge problem, but understand you did specifically ask for a lossless solution, so...

Lossless (but way more complicated!)

There are technical limitations as to how precisely you can cut a video without having to re-encode at least some part of it, and it basically depends on the i-frame frequency. If every frame is an i-frame, you can cut anywhere, but if they're only every few seconds, then you can only cut losslessly at those i-frames without losing content or having to re-encode (at least part of the stream) so it can start with an i-frame.

ffmpeg

This SO Q&A specifically raises the question of how to cut between i-frames using ffmpeg. I don't know of any GUI apps to do this, but basically you run a command something like the following:

ffmpeg -i input.m4v -vcodec copy -acodec copy -ss 00:01:20.000 -t 00:37:50.000 output.m4v

The two times specified are start and duration, and can be specified either as seconds or hh:mm:ss.ss, and the -acodec copy and -vcodec copy tell ffmpeg not to re-encode.

I'm not exactly sure what happens if you cut too early, but I think the video is essentially blank (or maybe corrupt, depending on player) until it encounters an i-frame. So you'll probably want to find the nearest i-frame before your cut. This answer solves that problem using ffprobe and awk, albeit a little awkwardly. Essentially you use ffprobe to scan the frames and find the nearest keyframe (flags=K) before your ideal cut-point. Full output for each frame of the video can be seen like this:

ffprobe -select_streams v -show_frames <INPUT>

The linked answer supplies this command to find a keyframe before a specific time:

ffprobe -select_streams v -show_frames -v quiet INPUT.mp4 | 
awk -F= ' 
  /pict_type=/ { if (index($2, "I")) { i=1; } else { i=0; } } 
  /pkt_pts_time/ { if (i && ($2 >= 150)) print $2; }  
' | head -n 1

And finally, if you really need to cut somewhere between two i-frames, you can split the video and re-join. Based on the info from this answer, it should be something like:

ffmpeg -f concat -i list_of_videos.txt -c copy OUTPUT.mp4

Where list_of_videos.txt is a simple text file listing the files you want to concatenate.

Summary

iMovie is probably good enough for most cases (since v10), and very easy.

ffmpeg can do it losslessly (or very close to losslessly), with a bit of fiddling; level of difficulty depends on how picky you are about the precise starting point, and frequency of i-frames.


I made a graphical tool that uses ffmpeg to let you losslessly trim videos by selecting the start and end points on the timeline: https://github.com/mifi/lossless-cut

It is open source and cross platform.


Quicktime 7 Pro ($30)

Open your video. If you want to see the exact frame number: in the lower left, click on the timer to switch to "Frame Number" display.

lowerleft

Select the start point (type i when you are there) and end point (type o when you are there).
select
Move one frame at a time with the arrow keys; or drag the little handles on the bottom. (Here we see the end is at frame 1330.)

In the Edit menu, choose "Delete" to get rid of the selected portion, or choose "Trim" to get rid of everything else.
crop

Although Quicktime 7 will save only in MOOV format, it will export in many formats. Export as MPEG-4 (for example) and avoid re-coding by choosing option "Pass through"

options