Answers.Body: <p>This is possible to do, in theory. The key is to match all relevant source bitstream properties when encoding.</p>
  
  <p><strong>#1</strong> Segment source video</p>
  
  <pre><code>ffmpeg -i source.mp4 -c copy -an -f segment -segment_time 0.01 seg%d.ts
  </code></pre>
  
  <p>Since the segment muxer by default only splits at keyframes, by providing a very low segment time, each produced segment will be one GOP long.</p>
  
  <p>(I suggest using the whole audio from the source, we don't extract it here)</p>
  
  <p><strong>#2</strong> Re-encode first segment</p>
  
  <pre><code>ffmpeg -i seg1.ts {-encoding args} -copyts -x264opts stitchable{+any-other-args} new1.ts
  </code></pre>
  
  <p>It's important here to match source settings.</p>
  
  <p><strong>#3</strong> Rejoin segments</p>
  
  <pre><code>ffmpeg -i "concat:new1.ts|seg2.ts|..." -i source.mp4 -c copy -map 0 -map 1:a new.mp4
  </code></pre>
  
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2018-03-06T18:33:34.940Z
Answers.Text: This is a partial solution but doesn't solve the original question. Doing this as-is will simply re-encode the first GOP, but without truncating it. I tried re-encoding the first GOP with the `-ss` option, which worked, but then when I use the `concat` protocol there is a gap between the last frame of the newly encoded GOP and the first frame of the next one, which is exactly the length I cut off the beginning. It appears to be a timestamp issue. I tried using the concat demuxer, but that messes up the framerate of the video (and thus changes its length and messes up audio sync).
Answers.UserDisplayName: mngeek206
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2018-03-06T18:58:38.150Z
Answers.Text: Add `-reset timestamps 1` to step 1 command and use the concat  demuxer in step 3.
Answers.UserDisplayName: Gyan
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2018-03-06T19:02:54.927Z
Answers.Text: Or with my original set of cmds, use `-copyts` in step 2.
Answers.UserDisplayName: Gyan
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2018-03-06T19:14:24.197Z
Answers.Text: I fixed it by adding `-copyts -start-at-zero` to the step where I re-encode the first GOP of the video. I also had to write a Python script to generate the huge list ( `seg2.ts|seg3.ts|...` ) but it does seem to work. I also was able to truncate off the end by simply re-encoding the final GOP with the `-t` parameter. I'm giving you the answer credit since you got me in the right direction, and I'll post a more complete list of what I had to do to make it work below.
Answers.UserDisplayName: mngeek206
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2018-03-04T06:53:45.280Z
Answers.LastActivityDate: 2018-03-04T06:53:45.280Z
Answers.UserDisplayName: Gyan
Answers.Body: <p>I gave answer credit to @Mulvya since that post got me in the right direction. Here is what I did to trim off the beginning of the video files:</p>
  
  <ol>
  <li><code>ffmpeg -i source.mp4 -c copy -an -f segment -segment_time 0.01 seg%04d.ts</code> - This split the source stream into hundreds of segments, one per GOP of source video.</li>
  <li><code>ffmpeg -ss 00:00:01.5 -i seg0000.ts -c:v libx264 -copyts -start_at_zero -x264opts stitchable -profile:v high -level 5.0 -crf 18 seg0000a.ts</code> - This encodes the first GOP to a new ts stream, truncating off the beginning 1.5 seconds. 
  
  <ul>
  <li>A few files wouldn't truncate correctly, so I first converted them to lossless <code>FFV1</code> video: <code>ffmpeg -i seg0000.ts -c:v ffv1 -level 1 -coder 1 -context 1 -g 1 seg0000.mkv</code> and then executed the above command against the <code>.mkv</code> file. </li>
  </ul></li>
  <li>To trim off from the end of the video, I encoded the final GOP truncating it: <code>ffmpeg -t 00:00:03.20 -i seg1044.ts  -c:v libx264 -copyts -x264opts stitchable -profile high -level 5.0 seg1044a.ts</code> - This encodes only the first 3.2 seconds of the final GOP, truncating the rest. (GOPs in the source video were about 5 seconds each, so this truncated 1.8 seconds.)</li>
  <li><code>ffmpeg -i source.mp4 -c copy -vn audio.m4a</code> - extract the audio</li>
  <li>Trim the audio using an external tool. <code>MP3DirectCut</code> can do frame-accurate trimming of M4A/AAC audio, and <code>delaycut</code> can do frame-accurate trimming of AC3/EAC3/DTS audio.</li>
  <li>Used a python script to generate a string containing all the <code>.ts</code> files. There's lots of ways to accomplish this sort of thing. I ended up with a long string on the clipboard: <code>seg0000.ts|seg0001.ts|...|seg1044.ts</code></li>
  <li>Pasted this long string into a text editor and changed <code>seg0000.ts</code> and <code>seg1044.ts</code> to <code>seg000a.ts</code> and <code>seg1044a.ts</code> respectively.</li>
  <li>Combine the video segments: <code>ffmpeg -fflags +igndts -i "concat:{string generated in steps 6-7 here}" -c copy -fflags +genpts video.mkv</code></li>
  <li>Finally, re-combine the trimmed audio: <code>ffmpeg -i video.mkv -i audio.m4a -c copy -map 0:0 -map 1:0 final-video.mp4</code></li>
  </ol>
  
  <p>I imagine this process could probably be optimized further, but this is what ultimately worked after messing with it for over an hour.</p>
  
  <p>(Hint: I found it convenient to extract all the frames of one GOP to .png files for easy browsing to determine which frame to cut at. For example: <code>ffmpeg -i seg0000.ts seg0000-frame%03d.png</code>)</p>
  
  <hr>
  
  <p>EDIT: This is the Python script I wrote to generate the <code>concat:</code> list:</p>
  
  <pre><code># ffconcat.py
  
  import sys
  from os.path import basename
  from os import listdir
  
  if (len(sys.argv) &lt; 2):
          print("Syntax: %s [extension]" % (sys.argv[0], ))
          exit(1)
  
  filelist = list(filter(lambda y: y.endswith("."+sys.argv[1]), sorted([basename(x) for x in listdir('.')])))
  filestring = "|".join(filelist)
  
  sys.stdout.write("concat:"+filestring)
  sys.stdout.flush()
  </code></pre>
  
  <p>You could use it in step 7 by first removing the "original" .ts files (e.g. <code>seg000.ts</code>) and then using it like:</p>
  
  <pre><code>ffmpeg -fflags +igndts -i `python3 ffconcat.py ts` -c copy -fflags +genpts video.mkv
  </code></pre>
  
  <p>This script is very simple (it only scans the current directory) so if you wanted to put the muxed video elsewhere you could, for example:</p>
  
  <pre><code>ffmpeg -fflags +igndts -i "concat:{string generated in steps 6-7 here}" -c copy -fflags +genpts ../video.mkv
  </code></pre>
  
  <p>Feel free to use/improve this script.</p>
  
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2018-03-07T04:58:11.413Z
Answers.Text: *To trim off from the end of the video* --> no need to re-encode if trimming off the end. `start_at_zero` is only required if `ss` is before the input `-i`.
Answers.UserDisplayName: Gyan
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2018-03-06T19:24:54.677Z
Answers.LastActivityDate: 2018-03-06T23:18:46.053Z
Answers.LastEditDate: 2018-03-06T23:18:46.053Z
Answers.UserDisplayName: mngeek206
Answers.Body: <p><a href="http://avidemux.sourceforge.net/" rel="nofollow noreferrer">Avidemux</a> is a simple, open-source video editor which allows for trimming clips without re-encoding. You open your video, choose the trimming marks, and set the "Video Output" to "Copy" before saving.</p>
  
  <p>Here is a tutorial on using it for lossless trimming:<br>
  <a href="https://steemit.com/videography/@phloatingman/tutorial-how-to-trim-a-video-without-transcoding-using-avidemux" rel="nofollow noreferrer">https://steemit.com/videography/@phloatingman/tutorial-how-to-trim-a-video-without-transcoding-using-avidemux</a></p>
  
  <p>Internally because of the way H.264 works, you can trim trailing P/B frames from a GOP, but if you trim out an I frame, you will need to trim out the entire GOP. Avidemux warns you of this. If you needed an exact trim and it fell mid-GOP you might need to make two clips (with a re-encoding of only the first one) and then join them in Avidemux.</p>
  
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2019-08-12T05:46:30.727Z
Answers.LastActivityDate: 2019-08-16T07:18:08.280Z
Answers.LastEditDate: 2019-08-16T07:18:08.280Z
Answers.UserDisplayName: Simon East
Body: <p>My scenario is this: I have a few .mp4 files containing H264 video with AAC audio. Each file was encoded from a DVR source. There are a few frames too many at both the beginning and end of the file (less than 1 second worth). I want to edit off these few frames.</p>
  
  <p>The problem is that I can tell that the first keyframe falls a couple seconds into the desired video. </p>
  
  <p>I'd like to chop the first few undesired frames off of the video, but I'd like to not have to re-encode the entire file because this comes with the inherent generation loss of re-encoding already compressed video (and the time taken).</p>
  
  <p>(I'm ignoring audio issues for the moment - for MP3 there are frame-level editors like MP3DirectCut and I think there's something similar for AAC audio. I can use ffmpeg to split the two streams out and work with them independently and then later remux them into a new .mp4 file.)</p>
  
  <p>Here's a simple illustration of what I'd like to do:</p>
  
  <pre><code>Source file
  |------GOP---------|------GOP---------|------GOP-----|
  IBBPBBPBBPBBPBBPBBPIBBPBBPBBPBBPBBPBBPIBBPBBPBBPBBPBBI...
  ^   ^     
  |   first desired frame
  - undesired frame(s)
  
  Re-encoded first GOP, other GOPs copied losslessly:
  |----New GOP----|------GOP---------|------GOP-----|
  IBPBBPBBPBBPBBBPIBBPBBPBBPBBPBBPBBPIBBPBBPBBPBBPBBI
  |               |
  +---------------+
  re-encode just these
  frames to a new short
  GOP, copy all remaining
  GOPs losslessly
  </code></pre>
  
  <p>I could be completely wrong, but my understanding of video encoding leads me to believe that GOPs are independent sets of frames that can stand alone; you need all of the frames of a GOP to decode the GOP, but one GOP will not be dependent upon another GOP. So, unless that assumption is completely wrong, I imagine something like this should work, theoretically:</p>
  
  <ol>
  <li>Re-encode the first couple of seconds of the video, starting at the desired frame, using the same settings (profile, level, etc.) that encoded the original source. I'd need to be able to do one of the following: 
  
  <ul>
  <li>Extract off the first GOP of this newly-encoded file, and truncate that GOP so it ends on the frame right before the keyframe of the next GOP in the original file.</li>
  <li>Specify a hard limit on the number of frames per GOP during encoding, so that I could then extract off the first GOP and it would already be the correct size.</li>
  </ul></li>
  <li>Take this new shortened GOP and append all but the first GOP of the original file. The end result would be a new H264 stream where <em>only the first GOP</em> has been re-encoded; all the rest of the GOPs would be copied losslessly.</li>
  </ol>
  
  <p>I'm not necessarily against a paid tool, but pretty much any NLE is going to involve re-encoding the video at some stage. My goal is to bring as much as possible over from the original video losslessly. (Basically, if I could do this, the only area I'd be suffering any generation loss is in the first second of the file, which is likely to be a fade-in or even some black frames and of little importance to the overall presentation.)</p>
  
  <p>Can this be done??</p>
  
Comments.ContentLicense: CC BY-SA 3.0
Comments.CreationDate: 2018-03-04T01:33:12.547Z
Comments.Text: FYI, GOP nomenclature, I frames are generally equivalent to your key frames. P and B frames are equal to your I's. You may want to update your example so that people aren't confused. You should also be aware that depending on your user case, variable GOP lengths can cause problems.
Comments.UserDisplayName: Michael Liebman
Tags: <editing><h.264><gop>
Title: Can you losslessly ediit H264 at the GOP level?
UserDisplayName: mngeek206
ThreadText: # Can you losslessly ediit H264 at the GOP level?
  
  (Asked by: username_0 on 2018-03-04)
  
  My scenario is this: I have a few .mp4 files containing H264 video with AAC audio. Each file was encoded from a DVR source. There are a few frames too many at both the beginning and end of the file (less than 1 second worth). I want to edit off these few frames.
  
  The problem is that I can tell that the first keyframe falls a couple seconds into the desired video.
  
  I'd like to chop the first few undesired frames off of the video, but I'd like to not have to re-encode the entire file because this comes with the inherent generation loss of re-encoding already compressed video (and the time taken).
  
  (I'm ignoring audio issues for the moment - for MP3 there are frame-level editors like MP3DirectCut and I think there's something similar for AAC audio. I can use ffmpeg to split the two streams out and work with them independently and then later remux them into a new .mp4 file.)
  
  Here's a simple illustration of what I'd like to do:
  
  ```
  Source file
  |------GOP---------|------GOP---------|------GOP-----|
  IBBPBBPBBPBBPBBPBBPIBBPBBPBBPBBPBBPBBPIBBPBBPBBPBBPBBI...
  ^   ^     
  |   first desired frame
  - undesired frame(s)
  
  Re-encoded first GOP, other GOPs copied losslessly:
  |----New GOP----|------GOP---------|------GOP-----|
  IBPBBPBBPBBPBBBPIBBPBBPBBPBBPBBPBBPIBBPBBPBBPBBPBBI
  |               |
  +---------------+
  re-encode just these
  frames to a new short
  GOP, copy all remaining
  GOPs losslessly
  
  ```
  
  I could be completely wrong, but my understanding of video encoding leads me to believe that GOPs are independent sets of frames that can stand alone; you need all of the frames of a GOP to decode the GOP, but one GOP will not be dependent upon another GOP. So, unless that assumption is completely wrong, I imagine something like this should work, theoretically:
  
  1. Re-encode the first couple of seconds of the video, starting at the desired frame, using the same settings (profile, level, etc.) that encoded the original source. I'd need to be able to do one of the following:
     * Extract off the first GOP of this newly-encoded file, and truncate that GOP so it ends on the frame right before the keyframe of the next GOP in the original file.
     * Specify a hard limit on the number of frames per GOP during encoding, so that I could then extract off the first GOP and it would already be the correct size.
  2. Take this new shortened GOP and append all but the first GOP of the original file. The end result would be a new H264 stream where *only the first GOP* has been re-encoded; all the rest of the GOPs would be copied losslessly.
  
  I'm not necessarily against a paid tool, but pretty much any NLE is going to involve re-encoding the video at some stage. My goal is to bring as much as possible over from the original video losslessly. (Basically, if I could do this, the only area I'd be suffering any generation loss is in the first second of the file, which is likely to be a fade-in or even some black frames and of little importance to the overall presentation.)
  
  Can this be done??
  
  **Tags:** editing, h.264, gop
  
  > **Comments:**
  > **username_1**: FYI, GOP nomenclature, I frames are generally equivalent to your key frames. P and B frames are equal to your I's. You may want to update your example so that people aren't confused. You should also be aware that depending on your user case, variable GOP lengths can cause problems.  
  
  ---
  
  ## 3 answers
  
  ### Answer by username_2 on 2018-03-04. Score: 2 | Accepted answer
  
  This is possible to do, in theory. The key is to match all relevant source bitstream properties when encoding.
  
  **#1** Segment source video
  
  ```
  ffmpeg -i source.mp4 -c copy -an -f segment -segment_time 0.01 seg%d.ts
  
  ```
  
  Since the segment muxer by default only splits at keyframes, by providing a very low segment time, each produced segment will be one GOP long.
  
  (I suggest using the whole audio from the source, we don't extract it here)
  
  **#2** Re-encode first segment
  
  ```
  ffmpeg -i seg1.ts {-encoding args} -copyts -x264opts stitchable{+any-other-args} new1.ts
  
  ```
  
  It's important here to match source settings.
  
  **#3** Rejoin segments
  
  ```
  ffmpeg -i "concat:new1.ts|seg2.ts|..." -i source.mp4 -c copy -map 0 -map 1:a new.mp4
  
  ```
  
  > **Comments:**
  > **username_0**: This is a partial solution but doesn't solve the original question. Doing this as-is will simply re-encode the first GOP, but without truncating it. I tried re-encoding the first GOP with the `-ss` option, which worked, but then when I use the `concat` protocol there is a gap between the last frame of the newly encoded GOP and the first frame of the next one, which is exactly the length I cut off the beginning. It appears to be a timestamp issue. I tried using the concat demuxer, but that messes up the framerate of the video (and thus changes its length and messes up audio sync).  
  > **username_2**: Add `-reset timestamps 1` to step 1 command and use the concat  demuxer in step 3.  
  > **username_2**: Or with my original set of cmds, use `-copyts` in step 2.  
  > **username_0**: I fixed it by adding `-copyts -start-at-zero` to the step where I re-encode the first GOP of the video. I also had to write a Python script to generate the huge list ( `seg2.ts|seg3.ts|...` ) but it does seem to work. I also was able to truncate off the end by simply re-encoding the final GOP with the `-t` parameter. I'm giving you the answer credit since you got me in the right direction, and I'll post a more complete list of what I had to do to make it work below.  
  
  ---
  
  ### Answer by username_0 on 2018-03-06. Score: 0
  
  I gave answer credit to @Mulvya since that post got me in the right direction. Here is what I did to trim off the beginning of the video files:
  
  1. `ffmpeg -i source.mp4 -c copy -an -f segment -segment_time 0.01 seg%04d.ts` - This split the source stream into hundreds of segments, one per GOP of source video.
  2. `ffmpeg -ss 00:00:01.5 -i seg0000.ts -c:v libx264 -copyts -start_at_zero -x264opts stitchable -profile:v high -level 5.0 -crf 18 seg0000a.ts` - This encodes the first GOP to a new ts stream, truncating off the beginning 1.5 seconds.
     * A few files wouldn't truncate correctly, so I first converted them to lossless `FFV1` video: `ffmpeg -i seg0000.ts -c:v ffv1 -level 1 -coder 1 -context 1 -g 1 seg0000.mkv` and then executed the above command against the `.mkv` file.
  3. To trim off from the end of the video, I encoded the final GOP truncating it: `ffmpeg -t 00:00:03.20 -i seg1044.ts -c:v libx264 -copyts -x264opts stitchable -profile high -level 5.0 seg1044a.ts` - This encodes only the first 3.2 seconds of the final GOP, truncating the rest. (GOPs in the source video were about 5 seconds each, so this truncated 1.8 seconds.)
  4. `ffmpeg -i source.mp4 -c copy -vn audio.m4a` - extract the audio
  5. Trim the audio using an external tool. `MP3DirectCut` can do frame-accurate trimming of M4A/AAC audio, and `delaycut` can do frame-accurate trimming of AC3/EAC3/DTS audio.
  6. Used a python script to generate a string containing all the `.ts` files. There's lots of ways to accomplish this sort of thing. I ended up with a long string on the clipboard: `seg0000.ts|seg0001.ts|...|seg1044.ts`
  7. Pasted this long string into a text editor and changed `seg0000.ts` and `seg1044.ts` to `seg000a.ts` and `seg1044a.ts` respectively.
  8. Combine the video segments: `ffmpeg -fflags +igndts -i "concat:{string generated in steps 6-7 here}" -c copy -fflags +genpts video.mkv`
  9. Finally, re-combine the trimmed audio: `ffmpeg -i video.mkv -i audio.m4a -c copy -map 0:0 -map 1:0 final-video.mp4`
  
  I imagine this process could probably be optimized further, but this is what ultimately worked after messing with it for over an hour.
  
  (Hint: I found it convenient to extract all the frames of one GOP to .png files for easy browsing to determine which frame to cut at. For example: `ffmpeg -i seg0000.ts seg0000-frame%03d.png`)
  
  ---
  
  EDIT: This is the Python script I wrote to generate the `concat:` list:
  
  ```
  # ffconcat.py
  
  import sys
  from os.path import basename
  from os import listdir
  
  if (len(sys.argv) < 2):
          print("Syntax: %s [extension]" % (sys.argv[0], ))
          exit(1)
  
  filelist = list(filter(lambda y: y.endswith("."+sys.argv[1]), sorted([basename(x) for x in listdir('.')])))
  filestring = "|".join(filelist)
  
  sys.stdout.write("concat:"+filestring)
  sys.stdout.flush()
  
  ```
  
  You could use it in step 7 by first removing the "original" .ts files (e.g. `seg000.ts`) and then using it like:
  
  ```
  ffmpeg -fflags +igndts -i `python3 ffconcat.py ts` -c copy -fflags +genpts video.mkv
  
  ```
  
  This script is very simple (it only scans the current directory) so if you wanted to put the muxed video elsewhere you could, for example:
  
  ```
  ffmpeg -fflags +igndts -i "concat:{string generated in steps 6-7 here}" -c copy -fflags +genpts ../video.mkv
  
  ```
  
  Feel free to use/improve this script.
  
  > **Comments:**
  > **username_2**: *To trim off from the end of the video* --> no need to re-encode if trimming off the end. `start_at_zero` is only required if `ss` is before the input `-i`.  
  
  ---
  
  ### Answer by username_3 on 2019-08-12. Score: 0
  
  [Avidemux](http://avidemux.sourceforge.net/) is a simple, open-source video editor which allows for trimming clips without re-encoding. You open your video, choose the trimming marks, and set the "Video Output" to "Copy" before saving.
  
  Here is a tutorial on using it for lossless trimming:  
  <https://steemit.com/videography/@phloatingman/tutorial-how-to-trim-a-video-without-transcoding-using-avidemux>
  
  Internally because of the way H.264 works, you can trim trailing P/B frames from a GOP, but if you trim out an I frame, you will need to trim out the entire GOP. Avidemux warns you of this. If you needed an exact trim and it fell mid-GOP you might need to make two clips (with a re-encoding of only the first one) and then join them in Avidemux.
  
  
  ---
  
  