Answers.Body: <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>
  
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2024-11-09T20:21:01.663Z
Answers.Text: Wow. Is this a new feature or did everyone else just do it wrong?
Answers.UserDisplayName: qwr
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2024-11-09T14:58:40.147Z
Answers.LastActivityDate: 2024-11-09T14:58:40.147Z
Answers.UserDisplayName: Gyan
Body: <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>
  
Tags: <ffmpeg><encoding>
Title: How did ffmpeg cut on a non-keyframe without re-encoding?
UserDisplayName: qwr
ThreadText: # 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?  
  
  ---
  
  