Blocky Video on M2 Mac Mini

I'm getting blocky video when using hardware transcoding on an M2 mac mini. When switching to software the video is no longer blocky. I would prefer to use hardware when possible, any idea why this is happening? HEVC is disabled and the stream info shows the video is h.264. Issue exists on a google tv streamer and an nvidia shield.

I dont know if this helps, but this is my debug info. I also submitted disagnostics from the nvidia shield client.

h264_videotoolbox

[Parsed_testsrc_0 @ 0x600003bfc840] size:1280x720 rate:60/1 duration:-1.000000 sar:1/1
Input #0, lavfi, from 'testsrc=size=1280x720:rate=60':
  Duration: N/A, start: 0.000000, bitrate: N/A
  Stream #0:0: Video: wrapped_avframe, 1 reference frame, rgb24, 1280x720 [SAR 1:1 DAR 16:9], 60 fps, 60 tbr, 60 tbn
[out#0/null @ 0x6000039fc3c0] No explicit maps, mapping streams automatically...
[vost#0:0/h264_videotoolbox @ 0x137e059e0] Created video stream from input stream 0:0
Stream mapping:
  Stream #0:0 -> #0:0 (wrapped_avframe (native) -> h264 (h264_videotoolbox))
Press [q] to stop, [?] for help
[graph 0 input from stream 0:0 @ 0x600003bf40b0] w:1280 h:720 pixfmt:rgb24 tb:1/60 fr:60/1 sar:1/1
[auto_scale_0 @ 0x600003bf82c0] w:iw h:ih flags:'' interl:0
[format @ 0x600003bf42c0] auto-inserting filter 'auto_scale_0' between the filter 'Parsed_null_0' and the filter 'format'
[auto_scale_0 @ 0x600003bf82c0] w:1280 h:720 fmt:rgb24 sar:1/1 -> w:1280 h:720 fmt:yuv420p sar:1/1 flags:0x00000004
Output #0, null, to '/dev/null':
  Metadata:
    encoder         : Lavf60.16.100
  Stream #0:0: Video: h264, 1 reference frame, yuv420p(tv, progressive), 1280x720 (0x0) [SAR 1:1 DAR 16:9], q=2-31, 4000 kb/s, 60 fps, 60 tbn
    Metadata:
      encoder         : Lavc60.31.102 h264_videotoolbox
No more output streams to write to, finishing.
[vist#0:0/wrapped_avframe @ 0x137e04650] Decoder thread received EOF packet
[vist#0:0/wrapped_avframe @ 0x137e04650] Decoder returned EOF, finishing
[vist#0:0/wrapped_avframe @ 0x137e04650] Terminating decoder thread
[out#0/null @ 0x6000039fc3c0] All streams finished
[out#0/null @ 0x6000039fc3c0] Terminating muxer thread
[out#0/null @ 0x6000039fc3c0] Output file #0 (/dev/null):
[out#0/null @ 0x6000039fc3c0]   Output stream #0:0 (video): 60 frames encoded; 60 packets muxed (98646 bytes); 
[out#0/null @ 0x6000039fc3c0]   Total: 60 packets (98646 bytes) muxed
[out#0/null @ 0x6000039fc3c0] video:96kB audio:0kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: unknown
frame=   60 fps=0.0 q=-0.0 Lsize=N/A time=00:00:00.98 bitrate=N/A speed=3.41x    
[AVIOContext @ 0x137f04420] Statistics: 337 bytes written, 0 seeks, 2 writeouts
[in#0/lavfi @ 0x6000030f8000] Terminating demuxer thread
[in#0/lavfi @ 0x6000030f8000] Input file #0 (testsrc=size=1280x720:rate=60):
[in#0/lavfi @ 0x6000030f8000]   Input stream #0:0 (video): 63 packets read (30240 bytes); 61 frames decoded; 0 decode errors; 
[in#0/lavfi @ 0x6000030f8000]   Total: 63 packets (30240 bytes) demuxed

success in 298ms

h264_videotoolbox+deint

[Parsed_testsrc_0 @ 0x6000022d0000] size:1280x720 rate:60/1 duration:-1.000000 sar:1/1
[auto_scale_0 @ 0x6000022d0210] w:iw h:ih flags:'' interl:0
[Parsed_tinterlace_1 @ 0x6000022d00b0] auto-inserting filter 'auto_scale_0' between the filter 'Parsed_testsrc_0' and the filter 'Parsed_tinterlace_1'
[auto_scale_0 @ 0x6000022d0210] w:1280 h:720 fmt:rgb24 sar:1/1 -> w:1280 h:720 fmt:yuv444p sar:1/1 flags:0x00000004
[Parsed_tinterlace_1 @ 0x6000022d00b0] mode:1 filter:off h:720 -> h:720
Input #0, lavfi, from 'testsrc=size=1280x720:rate=60,tinterlace=mode=1':
  Duration: N/A, start: 0.000000, bitrate: N/A
  Stream #0:0: Video: wrapped_avframe, 1 reference frame, yuv444p, 1280x720 [SAR 1:1 DAR 16:9], 30 fps, 30 tbr, 30 tbn
[out#0/null @ 0x6000020d0240] No explicit maps, mapping streams automatically...
[vost#0:0/h264_videotoolbox @ 0x12fe07840] Created video stream from input stream 0:0
[Parsed_deinterlace_metal_2 @ 0x6000022d86e0] Using Metal device: Apple M2
Stream mapping:
  Stream #0:0 -> #0:0 (wrapped_avframe (native) -> h264 (h264_videotoolbox))
Press [q] to stop, [?] for help
[Parsed_deinterlace_metal_2 @ 0x6000022c8160] Using Metal device: Apple M2
[graph 0 input from stream 0:0 @ 0x6000022d42c0] w:1280 h:720 pixfmt:yuv444p tb:1/30 fr:30/1 sar:1/1
[auto_scale_0 @ 0x6000022d4370] w:iw h:ih flags:'' interl:0
[trim_in_0_0 @ 0x6000022d4210] auto-inserting filter 'auto_scale_0' between the filter 'graph 0 input from stream 0:0' and the filter 'trim_in_0_0'
[auto_scale_0 @ 0x6000022d4370] w:1280 h:720 fmt:yuv444p sar:1/1 -> w:1280 h:720 fmt:nv12 sar:1/1 flags:0x00000004
    Last message repeated 3 times
[h264_videotoolbox @ 0x12fe07ab0] Using input frames context (format videotoolbox_vld) with h264_videotoolbox encoder.
Output #0, null, to '/dev/null':
  Metadata:
    encoder         : Lavf60.16.100
  Stream #0:0: Video: h264, 1 reference frame, videotoolbox_vld(tv, progressive), 1280x720 (0x0) [SAR 1:1 DAR 16:9], q=2-31, 4000 kb/s, 60 fps, 60 tbn
    Metadata:
      encoder         : Lavc60.31.102 h264_videotoolbox
No more output streams to write to, finishing.
[vist#0:0/wrapped_avframe @ 0x12fe067d0] Decoder thread received EOF packet
[vist#0:0/wrapped_avframe @ 0x12fe067d0] Decoder returned EOF, finishing
[vist#0:0/wrapped_avframe @ 0x12fe067d0] Terminating decoder thread
[out#0/null @ 0x6000020d0240] All streams finished
[out#0/null @ 0x6000020d0240] Terminating muxer thread
[out#0/null @ 0x6000020d0240] Output file #0 (/dev/null):
[out#0/null @ 0x6000020d0240]   Output stream #0:0 (video): 30 frames encoded; 30 packets muxed (62864 bytes); 
[out#0/null @ 0x6000020d0240]   Total: 30 packets (62864 bytes) muxed
[out#0/null @ 0x6000020d0240] video:61kB audio:0kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: unknown
frame=   30 fps=0.0 q=-0.0 Lsize=N/A time=00:00:00.96 bitrate=N/A speed=2.76x    
[AVIOContext @ 0x12fe04630] Statistics: 350 bytes written, 0 seeks, 2 writeouts
[in#0/lavfi @ 0x6000029dc000] Terminating demuxer thread
[in#0/lavfi @ 0x6000029dc000] Input file #0 (testsrc=size=1280x720:rate=60,tinterlace=mode=1):
[in#0/lavfi @ 0x6000029dc000]   Input stream #0:0 (video): 33 packets read (15840 bytes); 31 frames decoded; 0 decode errors; 
[in#0/lavfi @ 0x6000029dc000]   Total: 33 packets (15840 bytes) demuxed

success in 391ms

h264_videotoolbox+tonemap

[Parsed_testsrc_0 @ 0x6000001342c0] size:1280x720 rate:60/1 duration:-1.000000 sar:1/1
[auto_scale_0 @ 0x600000134580] w:iw h:ih flags:'' interl:0
[Parsed_format_1 @ 0x600000134370] auto-inserting filter 'auto_scale_0' between the filter 'Parsed_testsrc_0' and the filter 'Parsed_format_1'
[auto_scale_1 @ 0x600000134630] w:iw h:ih flags:'' interl:0
[Parsed_colorspace_2 @ 0x600000134420] auto-inserting filter 'auto_scale_1' between the filter 'Parsed_format_1' and the filter 'Parsed_colorspace_2'
[auto_scale_0 @ 0x600000134580] w:1280 h:720 fmt:rgb24 sar:1/1 -> w:1280 h:720 fmt:p010le sar:1/1 flags:0x00000004
[auto_scale_1 @ 0x600000134630] w:1280 h:720 fmt:p010le sar:1/1 -> w:1280 h:720 fmt:yuv420p10le sar:1/1 flags:0x00000004
    Last message repeated 3 times
Input #0, lavfi, from 'testsrc=size=1280x720:rate=60,format=p010le,colorspace=all=bt2020:iall=bt2020:fast=0':
  Duration: N/A, start: 0.000000, bitrate: N/A
  Stream #0:0: Video: wrapped_avframe, 1 reference frame, yuv420p10le(bt2020nc/bt2020/smpte2084), 1280x720 [SAR 1:1 DAR 16:9], 60 fps, 60 tbr, 60 tbn
[out#0/null @ 0x6000003380c0] No explicit maps, mapping streams automatically...
[vost#0:0/h264_videotoolbox @ 0x14d706f70] Created video stream from input stream 0:0
[Parsed_tonemap_metal_2 @ 0x600000138210] Using Metal device: Apple M2
Stream mapping:
  Stream #0:0 -> #0:0 (wrapped_avframe (native) -> h264 (h264_videotoolbox))
Press [q] to stop, [?] for help
[Parsed_tonemap_metal_2 @ 0x6000001380b0] Using Metal device: Apple M2
[graph 0 input from stream 0:0 @ 0x600000138630] w:1280 h:720 pixfmt:yuv420p10le tb:1/60 fr:60/1 sar:1/1
[auto_scale_0 @ 0x6000001386e0] w:iw h:ih flags:'' interl:0
[trim_in_0_0 @ 0x600000138580] auto-inserting filter 'auto_scale_0' between the filter 'graph 0 input from stream 0:0' and the filter 'trim_in_0_0'
[auto_scale_0 @ 0x6000001386e0] w:1280 h:720 fmt:yuv420p10le sar:1/1 -> w:1280 h:720 fmt:p010le sar:1/1 flags:0x00000004
    Last message repeated 3 times
[h264_videotoolbox @ 0x14d7071e0] Using input frames context (format videotoolbox_vld) with h264_videotoolbox encoder.
Output #0, null, to '/dev/null':
  Metadata:
    encoder         : Lavf60.16.100
  Stream #0:0: Video: h264, 1 reference frame, videotoolbox_vld(tv, bt709, progressive), 1280x720 (0x0) [SAR 1:1 DAR 16:9], q=2-31, 4000 kb/s, 60 fps, 60 tbn
    Metadata:
      encoder         : Lavc60.31.102 h264_videotoolbox
No more output streams to write to, finishing.
[vist#0:0/wrapped_avframe @ 0x14d705560] Decoder thread received EOF packet
[vist#0:0/wrapped_avframe @ 0x14d705560] Decoder returned EOF, finishing
[vist#0:0/wrapped_avframe @ 0x14d705560] Terminating decoder thread
[out#0/null @ 0x6000003380c0] All streams finished
[out#0/null @ 0x6000003380c0] Terminating muxer thread
[out#0/null @ 0x6000003380c0] Output file #0 (/dev/null):
[out#0/null @ 0x6000003380c0]   Output stream #0:0 (video): 60 frames encoded; 60 packets muxed (104867 bytes); 
[out#0/null @ 0x6000003380c0]   Total: 60 packets (104867 bytes) muxed
[out#0/null @ 0x6000003380c0] video:102kB audio:0kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: unknown
frame=   60 fps=0.0 q=-0.0 Lsize=N/A time=00:00:00.98 bitrate=N/A speed=3.79x    
[AVIOContext @ 0x14e004420] Statistics: 346 bytes written, 0 seeks, 2 writeouts
[in#0/lavfi @ 0x600000a34000] Terminating demuxer thread
[in#0/lavfi @ 0x600000a34000] Input file #0 (testsrc=size=1280x720:rate=60,format=p010le,colorspace=all=bt2020:iall=bt2020:fast=0):
[in#0/lavfi @ 0x600000a34000]   Input stream #0:0 (video): 63 packets read (30240 bytes); 61 frames decoded; 0 decode errors; 
[in#0/lavfi @ 0x600000a34000]   Total: 63 packets (30240 bytes) demuxed

success in 310ms

Bumping this thread. Just turned the server back to hardware encoding last night and I can confirm I still have the blocky issue on server version 2026.06.30.2012

Hardware encoding will always be more blocky than software.

You can only have 2 out of 3 for - Speed, quality, bitrate.

Software generally gives you quality and bitrate, but requires more processing power/is slower encoding.

Hardware usually gives you high speed encoding but either blows out bitrate or reduces the quality.

While remote streaming channels is going to cap your bitrate to a certain speed, hence why quality is right down.

So you just gotta decide whether you want software encoding and limit how many simultaneous streams you transcode, to get the higher quality - or go hardware and never have to think about it, and accept the lower quality

HEVC should be a lot better quality than h264 for the videotoolbox encoders too btw, so if your client can handle hevc, I would turn that on.