blob: 5eab20c0742b4a734f5eed5178ecd93c6c0f2ecb [file] [log] [blame]
Rucha Katakwar222c5312022-03-21 14:17:01 -07001# Copyright 2022 The Android Open Source Project
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7# http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14"""Utility functions for processing video recordings.
15"""
16# Each item in this list corresponds to quality levels defined per
17# CamcorderProfile. For Video ITS, we will currently test below qualities
18# only if supported by the camera device.
Rucha Katakwarb6847db2022-03-24 16:49:13 -070019import logging
20import os.path
21import subprocess
Rucha Katakwarb6847db2022-03-24 16:49:13 -070022
23
Rucha Katakwar089e6092022-03-30 11:19:26 -070024ITS_SUPPORTED_QUALITIES = (
Rucha Katakwar41133f92022-03-22 13:44:09 -070025 'HIGH',
26 '2160P',
27 '1080P',
28 '720P',
29 '480P',
30 'CIF',
31 'QCIF',
32 'QVGA',
33 'LOW',
34 'VGA'
Rucha Katakwar222c5312022-03-21 14:17:01 -070035)
Rucha Katakwar0ced2c32022-08-01 14:54:42 -070036
37LOW_RESOLUTION_SIZES = (
38 '176x144',
39 '192x144',
40)
Rucha Katakwarb6847db2022-03-24 16:49:13 -070041
42
Rucha Katakwar932bded2022-04-04 14:29:52 -070043def extract_key_frames_from_video(log_path, video_file_name):
Clemenz Portmann8d40e422022-04-28 10:29:01 -070044 """Returns a list of extracted key frames.
Rucha Katakwarb6847db2022-03-24 16:49:13 -070045
46 Ffmpeg tool is used to extract key frames from the video at path
Rucha Katakwar932bded2022-04-04 14:29:52 -070047 os.path.join(log_path, video_file_name).
48 The extracted key frames will have the name video_file_name with "_key_frame"
Rucha Katakwarb6847db2022-03-24 16:49:13 -070049 suffix to identify the frames for video of each quality.Since there can be
50 multiple key frames, each key frame image will be differentiated with it's
51 frame index.All the extracted key frames will be available in jpeg format
52 at the same path as the video file.
53
Rucha Katakwar05167b72022-05-25 13:42:32 -070054 The run time flag '-loglevel quiet' hides the information from terminal.
55 In order to see the detailed output of ffmpeg command change the loglevel
56 option to 'info'.
57
Rucha Katakwarb6847db2022-03-24 16:49:13 -070058 Args:
59 log_path: path for video file directory
Rucha Katakwar932bded2022-04-04 14:29:52 -070060 video_file_name: name of the video file.
Rucha Katakwarb6847db2022-03-24 16:49:13 -070061 Returns:
62 key_frame_files: A list of paths for each key frame extracted from the
Clemenz Portmann8d40e422022-04-28 10:29:01 -070063 video. Ex: VID_20220325_050918_0_CIF_352x288.mp4
Rucha Katakwarb6847db2022-03-24 16:49:13 -070064 """
Rucha Katakwar932bded2022-04-04 14:29:52 -070065 ffmpeg_image_name = f"{video_file_name.split('.')[0]}_key_frame"
Clemenz Portmann8d40e422022-04-28 10:29:01 -070066 ffmpeg_image_file_path = os.path.join(
67 log_path, ffmpeg_image_name + '_%02d.png')
Rucha Katakwarb6847db2022-03-24 16:49:13 -070068 cmd = ['ffmpeg',
Clemenz Portmann8d40e422022-04-28 10:29:01 -070069 '-skip_frame',
70 'nokey',
71 '-i',
72 os.path.join(log_path, video_file_name),
73 '-vsync',
74 'vfr',
75 '-frame_pts',
76 'true',
77 ffmpeg_image_file_path,
Rucha Katakwar05167b72022-05-25 13:42:32 -070078 '-loglevel',
79 'quiet',
Clemenz Portmann8d40e422022-04-28 10:29:01 -070080 ]
81 logging.debug('Extracting key frames from: %s', video_file_name)
82 _ = subprocess.call(cmd)
Rucha Katakwarb6847db2022-03-24 16:49:13 -070083 arr = os.listdir(os.path.join(log_path))
84 key_frame_files = []
85 for file in arr:
86 if '.png' in file and not os.path.isdir(file) and ffmpeg_image_name in file:
87 key_frame_files.append(file)
Rucha Katakwar2c49c452022-05-19 14:29:03 -070088
Rucha Katakwar2e8ab092022-05-26 10:31:40 -070089 logging.debug('Extracted key frames: %s', key_frame_files)
90 logging.debug('Length of key_frame_files: %d', len(key_frame_files))
Clemenz Portmann00c6ef32022-06-02 16:21:19 -070091 if not key_frame_files:
Rucha Katakwar2c49c452022-05-19 14:29:03 -070092 raise AssertionError('No key frames extracted. Check source video.')
93
Rucha Katakwarb6847db2022-03-24 16:49:13 -070094 return key_frame_files
95
96
97def get_key_frame_to_process(key_frame_files):
Clemenz Portmann8d40e422022-04-28 10:29:01 -070098 """Returns the key frame file from the list of key_frame_files.
Rucha Katakwarb6847db2022-03-24 16:49:13 -070099
100 If the size of the list is 1 then the file in the list will be returned else
101 the file with highest frame_index will be returned for further processing.
102
103 Args:
104 key_frame_files: A list of key frame files.
105 Returns:
106 key_frame_file to be used for further processing.
107 """
Rucha Katakwar312d64e2022-05-25 10:24:25 -0700108 if not key_frame_files:
109 raise AssertionError('key_frame_files list is empty.')
Rucha Katakwarb6847db2022-03-24 16:49:13 -0700110 key_frame_files.sort()
111 return key_frame_files[-1]
Avichal Rakeshf82d5262022-04-22 16:24:18 -0700112
113
114def extract_all_frames_from_video(log_path, video_file_name, img_format):
Clemenz Portmann8d40e422022-04-28 10:29:01 -0700115 """Extracts and returns a list of all extracted frames.
Avichal Rakeshf82d5262022-04-22 16:24:18 -0700116
117 Ffmpeg tool is used to extract all frames from the video at path
118 <log_path>/<video_file_name>. The extracted key frames will have the name
119 video_file_name with "_frame" suffix to identify the frames for video of each
120 size. Each frame image will be differentiated with its frame index. All
121 extracted key frames will be available in the provided img_format format at
122 the same path as the video file.
123
Rucha Katakwar05167b72022-05-25 13:42:32 -0700124 The run time flag '-loglevel quiet' hides the information from terminal.
125 In order to see the detailed output of ffmpeg command change the loglevel
126 option to 'info'.
127
Avichal Rakeshf82d5262022-04-22 16:24:18 -0700128 Args:
129 log_path: str; path for video file directory
130 video_file_name: str; name of the video file.
131 img_format: str; type of image to export frames into. ex. 'png'
132 Returns:
133 key_frame_files: An ordered list of paths for each frame extracted from the
134 video
135 """
136 logging.debug('Extracting all frames')
137 ffmpeg_image_name = f"{video_file_name.split('.')[0]}_frame"
138 logging.debug('ffmpeg_image_name: %s', ffmpeg_image_name)
139 ffmpeg_image_file_names = (
140 f'{os.path.join(log_path, ffmpeg_image_name)}_%03d.{img_format}')
141 cmd = [
142 'ffmpeg', '-i', os.path.join(log_path, video_file_name),
Rucha Katakwar05167b72022-05-25 13:42:32 -0700143 ffmpeg_image_file_names, '-loglevel', 'quiet'
Avichal Rakeshf82d5262022-04-22 16:24:18 -0700144 ]
145 _ = subprocess.call(cmd)
146
147 file_list = sorted(
148 [_ for _ in os.listdir(log_path) if (_.endswith(img_format)
149 and ffmpeg_image_name in _)])
Clemenz Portmann00c6ef32022-06-02 16:21:19 -0700150 if not file_list:
Rucha Katakwar2c49c452022-05-19 14:29:03 -0700151 raise AssertionError('No frames extracted. Check source video.')
152
Avichal Rakeshf82d5262022-04-22 16:24:18 -0700153 return file_list