
Ich versuche, beispielsweise 10 Frames aus einem bestimmten Video auszuwählen, möglichst mit der größten Vielfalt und den meisten Szenen. Ich würde gerne mit verschiedenen Auswahlszenarien experimentieren, aber das Gute ist, dass der Begriff von I-frame
automatisch Szenenwechsel bedeutet! Ich würde also gerne die I-Frames erhalten. Aber vielleicht gibt es viele I-Frames, also muss ich sie wahrscheinlich abtasten.
Wie kann ich in FFMpeg oder Python die Liste aller Frame-Nummern von I-Frames in einem Video abrufen? Ich möchte die Liste verwenden, um nur 10 davon auszuwählen und sie als PNG/JPEG zu speichern.
Antwort1
Dies scheint ein X/Y-Problem zu sein, daher schlage ich mehrere verschiedene Befehle vor:
Liste der Zeitstempel
Wenn Sie für jedes Keyframe eine Liste mit Zeitstempeln ausgeben möchten:
ffprobe -v error -skip_frame nokey -show_entries frame=pkt_pts_time -select_streams v -of csv=p=0 input
0.000000
2.502000
3.795000
6.131000
10.344000
12.554000
Beachten Sie das -skip_frame nokey
.
Filter auswählen
Eine weitere Methode ist die Verwendung vonFilter auswählenmit der scene
Option zur Ausgabe Ihrer Thumbnails:
ffmpeg -i input -vf "select=gt'(scene,0.4)',scale=160:-1" -vsync vfr %04d.png
Antwort2
Dadurch werden alle I-Frames als PNG-Bilder ausgegeben.
ffmpeg -i 2.flv -vf "select=eq(pict_type\,I)" -vsync vfr frame-%02d.png
Diesem Kommentar ist eine ähnliche Frage von superuser.com zuzuschreiben. Wie extrahiere ich alle Keyframes aus einem Videoclip?
Hoffe, das hilft. Prost.
Ian
Antwort3
Erkenntnisse gewinnen durchHier, ich konnte es tun mit ffprobe
:
def iframes():
if not os.path.exists(iframe_path):
os.mkdir(iframe_path)
command = 'ffprobe -v error -show_entries frame=pict_type -of default=noprint_wrappers=1'.split()
out = subprocess.check_output(command + [filename]).decode()
f_types = out.replace('pict_type=','').split()
frame_types = zip(range(len(f_types)), f_types)
i_frames = [x[0] for x in frame_types if x[1]=='I']
if i_frames:
cap = cv2.VideoCapture(filename)
for frame_no in i_frames:
cap.set(cv2.CAP_PROP_POS_FRAMES, frame_no)
ret, frame = cap.read()
outname = iframe_path+'i_frame_'+str(frame_no)+'.jpg'
cv2.imwrite(outname, frame)
cap.release()
print("I-Frame selection Done!!")
if __name__ == '__main__':
iframes()
Antwort4
Um den Frametyp aller Frames im Video abzurufen, können Sie die folgende Python-Funktion verwenden. Siehe OriginallösungHier.
def get_frames_metadata(file):
command = '"{ffexec}" -show_frames -print_format json "{filename}"'.format(ffexec='ffprobe', filename=file)
response_json = subprocess.check_output(command, shell=True, stderr=None)
frames = json.loads(response_json)["frames"]
frames_metadata, frames_type, frames_type_bool = [], [], []
for frame in frames:
if frame["media_type"] == "video":
video_frame = json.dumps(dict(frame), indent=4)
frames_metadata.append(video_frame)
frames_type.append(frame["pict_type"])
if frame["pict_type"] == "I":
frames_type_bool.append(True)
else:
frames_type_bool.append(False)
print(frames_type)
return frames_metadata, frames_type, frames_type_bool
Ausgabeergebnis:
['I', 'P', 'P', 'P', 'P', 'P', 'P', 'P', 'P', 'P', 'P', 'P', 'P', 'P', 'P', 'P', 'P', 'P', 'P', 'P', 'P', 'P', 'P', 'P', 'P', 'P', 'P', 'P', 'P', 'P', 'P', 'P', 'P', 'P', 'P', 'P', 'P', 'P', 'P', 'P', 'P', 'P', 'P', 'P', 'P', 'P', 'P', 'P', 'I', 'P']
Wobei I und P der Rahmentyp sind.