I am doing some remasterisation techniques on a video, and instead of using these techniques on the whole video at once I want to do them on the group of pictures(GOPs) of the video separately, so what I want to know is there any way to extract the group of pictures of a video which are generated by the codec.
-
1what did you try? What code/modules do you use? `cv2` can read frame by frame - so you can work with every frame (or group of frames) separatelly. `ffmpeg` should have also some options to select by seconds or frames. But frankly without your code it hard to say what you really doing. – furas Jul 21 '22 at 11:40
-
Ok i will tell you what i kind of remasterisation i did, firstly I took my video and I applied it to a deep learning algorithm for background removal, then I processed the video frame by frame in order to create a new video that represents the original video but from four viewports(just like the pepper's ghost videos), i hope this makes sense. – Ala BR Jul 21 '22 at 11:54
-
It is known that the codec will automatically create those groups of pictures, and I am trying to get those groups to do the processing on them separately. – Ala BR Jul 21 '22 at 12:02
-
write it in question, not in comments - more people will see it and more people may help you. But I was asking about code, not description. Code can be more useful because Stackoverflow is for fixing small problems in existing code, not to write all code from scratch. – furas Jul 21 '22 at 12:30
-
@BaccarAla According to [this post](https://stackoverflow.com/questions/14005110/how-to-split-a-video-using-ffmpeg-so-that-each-chunk-starts-with-a-key-frame), it looks like you need both FFmpeg and FFprobe and some code. What is the codec and format of the input video, and what is the codec and format of the output video segments? – Rotem Jul 21 '22 at 12:58
1 Answers
Group of pictures (GOP) applies all video frames starting from a key frame, and ends one frame before the next key frame.
(The above definition assumes "Close GOPs").
The following post have examples for splitting a video into GOPs, but there is no Python code sample and I am not sure if this script is actually working.
For splitting a video file into multiple files when each file is one GOP, we may use segment muxer with -segment_times
argument.
-segment_times
expects a list of timestamps. We shell provide a list of timestamps of all the key frames in the input file.
Let's start by building an input video file for testing (using FFmpeg CLI):
ffmpeg -y -f lavfi -i testsrc=size=192x108:rate=1:duration=100 -vcodec libx264 -g 10 in.mp4
The above command builds synthetic a video file with fixed GOP size of 10 frames (for testing).
The frames are numbered, so it's easy to follow...
Using FFprobe CLI for getting the timestamps of all the key-frames (for demonstrating the concept):
ffprobe -skip_frame nokey -select_streams v:0 -show_frames -show_entries frame=pkt_pts_time -of json in.mp4 > tmp.txt
(A similar command is going to be executed from Python).
The above command creates a text file with timestamps of all key-frames in JSON format:
{
"frames": [
...
{
"pkt_pts_time": "10.000000"
},
{
"pkt_pts_time": "20.000000"
},
...
}
The segment_times list is going to be: "10.000000,20.000000,30.000000..."
.
Using a Python script for programmatically splitting video file to GOPs:
Use FFprobe for getting the PTS timestamps of all key frames (get it in JSON format):
data = sp.run(['ffprobe', '-skip_frame', 'nokey', '-select_streams', 'v:0', '-show_frames', '-show_entries', 'frame=pkt_pts_time', '-of', 'json', in_file_name], stdout=sp.PIPE).stdout
Convert from JSON (string) to dictionary, and Get 'frames' out of the dictionary:
dict = json.loads(data) frames_dict = dict['frames']
Building a comma separated string of timestamps:
pts_list = [item['pkt_pts_time'] for item in frames_dict] segment_times = ",".join(pts_list)
Use FFmpeg for splitting the input video by timestamps (files:
out0000.mp4
,out0001.mp4
,out0002.mp4
):sp.run(['ffmpeg', '-i', in_file_name, '-codec', 'copy', '-f', 'segment', '-reset_timestamps', '1', '-segment_times', segment_times, 'out%04d.mp4'])
The above code uses subprocess module for executing FFmpeg and FFprobe within Python.
Make sure ffmpeg and ffprobe are in the exaction path.
Python code:
import subprocess as sp
import json
# Preparation: build synthetic video file for testing
# ffmpeg -y -f lavfi -i testsrc=size=192x108:rate=1:duration=100 -vcodec libx264 -g 10 in.mp4
in_file_name = 'in.mp4' # Input file name
# Use FFprobe for getting the PTS timestamps of all key frames (get it in JSON format).
data = sp.run(['ffprobe', '-skip_frame', 'nokey', '-select_streams', 'v:0', '-show_frames', '-show_entries', 'frame=pkt_pts_time', '-of', 'json', in_file_name], stdout=sp.PIPE).stdout
dict = json.loads(data) # Convert from JSON (string) to dictionary
frames_dict = dict['frames'] # Get 'frames' out of the dictionary
pts_list = [item['pkt_pts_time'] for item in frames_dict] # Convert to list: ['0.000000', '10.000000', '20.000000', ...]
segment_times = ",".join(pts_list) # Convert list to comma separated string: '0.000000,10.000000,20.000000,...'
# Use FFmpeg for splitting the input video by timestamps (files: out0000.mp4, out0001.mp4, out0002.mp4)
# Each segment file is going to be a GOP - start from key-frame, and end one frame before the next key-frame.
sp.run(['ffmpeg', '-i', in_file_name, '-codec', 'copy', '-f', 'segment', '-reset_timestamps', '1', '-segment_times', segment_times, 'out%04d.mp4'])
Note:
- The above solution may not work for all codecs and all file formats.
For example, H.265 codec has segmenting issues (due to FFmpeg limitations).

- 30,366
- 4
- 32
- 65
-
Thank you, this code helped me to split my video into many chunks, also I am trying to do this splitting based on scene change, in other words when the scene changes I want to get that part of the video in a single chunk if you have to know any algorithm that helps me detect scene changes and that can be integrated into your code tell me about, and thanks in advance, very much appreciated. – Ala BR Jul 23 '22 at 13:05
-
1I found [this post](https://stackoverflow.com/questions/35675529/using-ffmpeg-how-to-do-a-scene-change-detection-with-timecode). There is also [scdet](http://www.ffmpeg.org/ffmpeg-filters.html#toc-scdet-1) filter (I never tried it). In case we can get the timestamps of `scdet`, we have the option to pass it as list to `-segment_times`. – Rotem Jul 23 '22 at 16:41
-
Hi, I have tried your solution and it worked, I have also implemented the second solution mentioned in the post that you sent, but it only works for video with low frame rates per second(25-30), thanks for your support very much appreciated. – Ala BR Jul 26 '22 at 10:39