<p>Yes, when the start point of a MP4 (input -ss) is a non-keyframe, ffmpeg will feed frames from the preceding keyframe. In the output, all those preceding frames till the designated start point will have a negative timestamp. The MP4 muxer will store those frames but add an editlist for the track indicating to a player which frame is the intended start of the playback.</p>

CC BY-SA 4.0
2024-11-09T20:21:01.663Z
Wow. Is this a new feature or did everyone else just do it wrong?
qwr
CC BY-SA 4.0
2024-11-09T14:58:40.147Z
2024-11-09T14:58:40.147Z
Gyan
<p>Every answer I've seen online says this is not possible. However, using <code>c:v copy</code> on my ffmpeg 6.1 on Termux, it somehow did it: start on exactly the right frame without re-encoding everything. I am pretty sure I did not start exactly on a keyframe as I checked all nearby I-frames in ffprobe.</p>
<p>My only guess is that it kept all the frames back to the previous keyframe and simply doesn't show this to you, as I don't think any frame is re-encoded. But I cannot explain the mysteries of ffmpeg.</p>
<p>Debug output if anyone understands it</p>
<pre><code>$ ffmpeg -v 40 -ss 3:08 -to 4:04  -i 25-02.mp4 -c:v copy 25-02new.mp4
ffmpeg version 6.1 Copyright (c) 2000-2023 the FFmpeg developers
  built with Android (10552028, +pgo, +bolt, +lto, -mlgo, based on r487747d) clang version 17.0.2 (https://android.googlesource.com/toolchain/llvm-project d9f89f4d16663d5012e5c09495f3b30ece3d2362)
  configuration: --arch=aarch64 --as=aarch64-linux-android-clang --cc=aarch64-linux-android-clang --cxx=aarch64-linux-android-clang++ --nm=llvm-nm --pkg-config=/home/builder/.termux-build/_cache/android-r26b-api-24-v0/bin/pkg-config --strip=llvm-strip --cross-prefix=aarch64-linux-android- --disable-indevs --disable-outdevs --enable-indev=lavfi --disable-static --disable-symver --enable-cross-compile --enable-gnutls --enable-gpl --enable-version3 --enable-jni --enable-lcms2 --enable-libaom --enable-libass --enable-libbluray --enable-libdav1d --enable-libfreetype --enable-libgme --enable-libmp3lame --enable-libopencore-amrnb --enable-libopencore-amrwb --enable-libopenmpt --enable-libopus --enable-librav1e --enable-libsoxr --enable-libsrt --enable-libssh --enable-libsvtav1 --enable-libtheora --enable-libv4l2 --enable-libvidstab --enable-libvo-amrwbenc --enable-libvorbis --enable-libvpx --enable-libwebp --enable-libx264 --enable-libx265 --enable-libxml2 --enable-libxvid --enable-libzimg --enable-mediacodec --enable-opencl --enable-shared --prefix=/data/data/com.termux/files/usr --target-os=android --extra-libs=-landroid-glob --disable-vulkan --enable-neon --disable-libfdk-aac
  libavutil      58. 29.100 / 58. 29.100
  libavcodec     60. 31.102 / 60. 31.102
  libavformat    60. 16.100 / 60. 16.100
  libavdevice    60.  3.100 / 60.  3.100
  libavfilter     9. 12.100 /  9. 12.100
  libswscale      7.  5.100 /  7.  5.100
  libswresample   4. 12.100 /  4. 12.100
  libpostproc    57.  3.100 / 57.  3.100
[h264 @ 0xb400007824156510] Reinit context to 416x720, pix_fmt: yuv420p
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from '25-02.mp4':
  Metadata:
    major_brand     : isom
    minor_version   : 512                                   compatible_brands: isomiso2avc1mp41
    encoder         : Lavf58.45.100
  Duration: 00:08:25.70, start: 0.000000, bitrate: 1132 kb/s
  Stream #0:0[0x1](und): Video: h264 (High), 1 reference frame (avc1 / 0x31637661), yuv420p(progressive, left), 404x720 (416x720) [SAR 405:404 DAR 9:16], 1129 kb/s, 30 fps, 30 tbr, 15360 tbn (default)                            Metadata:
      handler_name    : VideoHandler
      vendor_id       : [0][0][0][0]
[out#0/mp4 @ 0xb4000077c41520b0] No explicit maps, mapping streams automatically...
[vost#0:0/copy @ 0xb400007814150a50] Created video stream from input stream 0:0
Output #0, mp4, to '25-02new.mp4':
  Metadata:
    major_brand     : isom                                  minor_version   : 512
    compatible_brands: isomiso2avc1mp41                     encoder         : Lavf60.16.100                       Stream #0:0(und): Video: h264 (High), 1 reference frame (avc1 / 0x31637661), yuv420p(progressive, left), 404x720 (0x0) [SAR 405:404 DAR 9:16], q=2-31, 1129 kb/s, 30 fps, 30 tbr, 15360 tbn (default)
    Metadata:
      handler_name    : VideoHandler                          vendor_id       : [0][0][0][0]                    Stream mapping:                                           Stream #0:0 -&gt; #0:0 (copy)
Press [q] to stop, [?] for help
size=       0kB time=-00:00:00.33 bitrate=  -0.0kbits/s No more output streams to write to, finishing.
[out#0/mp4 @ 0xb4000077c41520b0] All streams finished
[out#0/mp4 @ 0xb4000077c41520b0] Terminating muxer thread
[AVIOContext @ 0xb4000077e414bb90] Statistics: 7069406 bytes written, 2 seeks, 30 writeouts
[out#0/mp4 @ 0xb4000077c41520b0] Output file #0 (25-02new.mp4):
[out#0/mp4 @ 0xb4000077c41520b0]   Output stream #0:0 (video): 1690 packets muxed (7050140 bytes);
[out#0/mp4 @ 0xb4000077c41520b0]   Total: 1690 packets (7050140 bytes) muxed
[out#0/mp4 @ 0xb4000077c41520b0] video:6885kB audio:0kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: 0.273214%
size=    6904kB time=00:00:55.96 bitrate=1010.5kbits/s speed=1.18e+03x
[in#0/mov,mp4,m4a,3gp,3g2,mj2 @ 0xb4000077d4157490] Terminating demuxer thread
[in#0/mov,mp4,m4a,3gp,3g2,mj2 @ 0xb4000077d4157490] Input file #0 (25-02.mp4):
[in#0/mov,mp4,m4a,3gp,3g2,mj2 @ 0xb4000077d4157490]   Input stream #0:0 (video): 1693 packets read (7053603 bytes);
[in#0/mov,mp4,m4a,3gp,3g2,mj2 @ 0xb4000077d4157490]   Total: 1693 packets (7053603 bytes) demuxed
[AVIOContext @ 0xb4000077e414cab0] Statistics: 7274496 bytes read, 1 seeks
</code></pre>

<ffmpeg><encoding>
How did ffmpeg cut on a non-keyframe without re-encoding?
qwr
# How did ffmpeg cut on a non-keyframe without re-encoding?

(Asked by: username_0 on 2024-11-09)

Every answer I've seen online says this is not possible. However, using c:v copy on my ffmpeg 6.1 on Termux, it somehow did it: start on exactly the right frame without re-encoding everything. I am pretty sure I did not start exactly on a keyframe as I checked all nearby I-frames in ffprobe.
My only guess is that it kept all the frames back to the previous keyframe and simply doesn't show this to you, as I don't think any frame is re-encoded. But I cannot explain the mysteries of ffmpeg.
Debug output if anyone understands it
$ ffmpeg -v 40 -ss 3:08 -to 4:04  -i 25-02.mp4 -c:v copy 25-02new.mp4
ffmpeg version 6.1 Copyright (c) 2000-2023 the FFmpeg developers
  built with Android (10552028, +pgo, +bolt, +lto, -mlgo, based on r487747d) clang version 17.0.2 (https://android.googlesource.com/toolchain/llvm-project d9f89f4d16663d5012e5c09495f3b30ece3d2362)
  configuration: --arch=aarch64 --as=aarch64-linux-android-clang --cc=aarch64-linux-android-clang --cxx=aarch64-linux-android-clang++ --nm=llvm-nm --pkg-config=/home/builder/.termux-build/_cache/android-r26b-api-24-v0/bin/pkg-config --strip=llvm-strip --cross-prefix=aarch64-linux-android- --disable-indevs --disable-outdevs --enable-indev=lavfi --disable-static --disable-symver --enable-cross-compile --enable-gnutls --enable-gpl --enable-version3 --enable-jni --enable-lcms2 --enable-libaom --enable-libass --enable-libbluray --enable-libdav1d --enable-libfreetype --enable-libgme --enable-libmp3lame --enable-libopencore-amrnb --enable-libopencore-amrwb --enable-libopenmpt --enable-libopus --enable-librav1e --enable-libsoxr --enable-libsrt --enable-libssh --enable-libsvtav1 --enable-libtheora --enable-libv4l2 --enable-libvidstab --enable-libvo-amrwbenc --enable-libvorbis --enable-libvpx --enable-libwebp --enable-libx264 --enable-libx265 --enable-libxml2 --enable-libxvid --enable-libzimg --enable-mediacodec --enable-opencl --enable-shared --prefix=/data/data/com.termux/files/usr --target-os=android --extra-libs=-landroid-glob --disable-vulkan --enable-neon --disable-libfdk-aac
  libavutil      58. 29.100 / 58. 29.100
  libavcodec     60. 31.102 / 60. 31.102
  libavformat    60. 16.100 / 60. 16.100
  libavdevice    60.  3.100 / 60.  3.100
  libavfilter     9. 12.100 /  9. 12.100
  libswscale      7.  5.100 /  7.  5.100
  libswresample   4. 12.100 /  4. 12.100
  libpostproc    57.  3.100 / 57.  3.100
[h264 @ 0xb400007824156510] Reinit context to 416x720, pix_fmt: yuv420p
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from '25-02.mp4':
  Metadata:
    major_brand     : isom
    minor_version   : 512                                   compatible_brands: isomiso2avc1mp41
    encoder         : Lavf58.45.100
  Duration: 00:08:25.70, start: 0.000000, bitrate: 1132 kb/s
  Stream #0:0[0x1](und): Video: h264 (High), 1 reference frame (avc1 / 0x31637661), yuv420p(progressive, left), 404x720 (416x720) [SAR 405:404 DAR 9:16], 1129 kb/s, 30 fps, 30 tbr, 15360 tbn (default)                            Metadata:
      handler_name    : VideoHandler
      vendor_id       : [0][0][0][0]
[out#0/mp4 @ 0xb4000077c41520b0] No explicit maps, mapping streams automatically...
[vost#0:0/copy @ 0xb400007814150a50] Created video stream from input stream 0:0
Output #0, mp4, to '25-02new.mp4':
  Metadata:
    major_brand     : isom                                  minor_version   : 512
    compatible_brands: isomiso2avc1mp41                     encoder         : Lavf60.16.100                       Stream #0:0(und): Video: h264 (High), 1 reference frame (avc1 / 0x31637661), yuv420p(progressive, left), 404x720 (0x0) [SAR 405:404 DAR 9:16], q=2-31, 1129 kb/s, 30 fps, 30 tbr, 15360 tbn (default)
    Metadata:
      handler_name    : VideoHandler                          vendor_id       : [0][0][0][0]                    Stream mapping:                                           Stream #0:0 -> #0:0 (copy)
Press [q] to stop, [?] for help
size=       0kB time=-00:00:00.33 bitrate=  -0.0kbits/s No more output streams to write to, finishing.
[out#0/mp4 @ 0xb4000077c41520b0] All streams finished
[out#0/mp4 @ 0xb4000077c41520b0] Terminating muxer thread
[AVIOContext @ 0xb4000077e414bb90] Statistics: 7069406 bytes written, 2 seeks, 30 writeouts
[out#0/mp4 @ 0xb4000077c41520b0] Output file #0 (25-02new.mp4):
[out#0/mp4 @ 0xb4000077c41520b0]   Output stream #0:0 (video): 1690 packets muxed (7050140 bytes);
[out#0/mp4 @ 0xb4000077c41520b0]   Total: 1690 packets (7050140 bytes) muxed
[out#0/mp4 @ 0xb4000077c41520b0] video:6885kB audio:0kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: 0.273214%
size=    6904kB time=00:00:55.96 bitrate=1010.5kbits/s speed=1.18e+03x
[in#0/mov,mp4,m4a,3gp,3g2,mj2 @ 0xb4000077d4157490] Terminating demuxer thread
[in#0/mov,mp4,m4a,3gp,3g2,mj2 @ 0xb4000077d4157490] Input file #0 (25-02.mp4):
[in#0/mov,mp4,m4a,3gp,3g2,mj2 @ 0xb4000077d4157490]   Input stream #0:0 (video): 1693 packets read (7053603 bytes);
[in#0/mov,mp4,m4a,3gp,3g2,mj2 @ 0xb4000077d4157490]   Total: 1693 packets (7053603 bytes) demuxed
[AVIOContext @ 0xb4000077e414cab0] Statistics: 7274496 bytes read, 1 seeks

**Tags:** ffmpeg, encoding


---

## 1 answers

### Answer by username_1 on 2024-11-09. Score: 2 | Accepted answer

Yes, when the start point of a MP4 (input -ss) is a non-keyframe, ffmpeg will feed frames from the preceding keyframe. In the output, all those preceding frames till the designated start point will have a negative timestamp. The MP4 muxer will store those frames but add an editlist for the track indicating to a player which frame is the intended start of the playback.

> **Comments:**
> **username_0**: Wow. Is this a new feature or did everyone else just do it wrong?  

---

