This is a code sample for reducing the drone captured aerial video to a workable set for drone world analysis:
import requests
import os
from dotenv import load_dotenv
load_dotenv(override=True)
import time
video_indexer_endpoint = os.getenv("AZURE_VIDEO_INDEXER_URL", "https://api.videoindexer.ai")
video_indexer_region = os.getenv("AZURE_VIDEO_INDEXER_REGION", "eastus")
video_indexer_account_id = os.getenv("AZURE_VIDEO_INDEXER_ACCOUNT")
video_Indexer_api_key = os.getenv("AZURE_VIDEO_INDEXER_API_KEY")
video_indexer_project = os.getenv("AZURE_VIDEO_INDEXER_PROJECT", "wfmat1ysct")
video_file_path = os.getenv("AZURE_VIDEO_INPUT", "mainindexedvideo.mp4")
access_token = os.getenv("AZURE_VIDEO_INDEXER_ACCESS_TOKEN")
video_id = os.getenv("AZURE_VIDEO_ID", "lwxjba8wy3")
duration = os.getenv("AZURE_VIDEO_DURATION_IN_SECONDS", "307")
def get_access_token():
"""Retrieve an access token for the Video Indexer API."""
url = f"{video_indexer_endpoint}/auth/{video_indexer_region}/Accounts/{video_indexer_account_id}/AccessToken"
headers = {
"Ocp-Apim-Subscription-Key": video_Indexer_api_key
}
response = requests.get(url, headers=headers)
return response.text.strip('"')
def repeat_video_index(access_token, video_id):
"""Retrieve the index/insights for a video by its ID."""
url = f"{video_indexer_endpoint}/{video_indexer_region}/Accounts/{video_indexer_account_id}/Videos/{video_id}/ReIndex?accessToken={access_token}"
response = requests.put(url)
if response.status_code == 200:
return response
return get_video_insights(access_token, video_id)
def get_video_insights(access_token, video_id):
url = f"{video_indexer_endpoint}/{video_indexer_region}/Accounts/{video_indexer_account_id}/Videos/{video_id}/Index?accessToken={access_token}"
count = 0
while True:
response = requests.get(url)
data = response.json()
if "state" in data and data['state'] == 'Processed':
return data
count+=1
if count%10 == 0:
print(data)
print("Sleeping for ten seconds...")
time.sleep(10) # Wait 10 seconds before checking again
def get_selected_segments(insights, threshold):
indexed_duration = insights["summarizedInsights"]["duration"]["seconds"]
reduced_duration = (threshold * indexed_duration) / 100
selected_segments = []
# total_duration = 0
for video in insights["videos"]:
for shot in video["insights"]["shots"]:
shot_id = shot["id"]
for key_frame in shot["keyFrames"]:
key_frame_id = key_frame["id"]
start = key_frame["instances"][0]["start"]
end = key_frame["instances"][0]["end"]
# total_duration += float(end) - float(start)
print(f"Clipping shot: {shot_id}, key_frame: {key_frame_id}, start: {start}, end: {end}")
selected_segments +=[(start,end)]
# print(f"Total duration: {total_duration}")
return selected_segments
def create_project(access_token, video_id, selected_segments):
import random
import string
video_ranges = []
for start,end in selected_segments:
intervals = {}
intervals["videoId"] = video_id
intervalRange = {}
intervalRange["start"] = start
intervalRange["end"] = end
intervals["range"] = intervalRange
video_ranges += [intervals]
project_name = ''.join(random.choices(string.hexdigits, k=8))
data = {
"name": project_name,
"videosRanges": video_ranges,
"isSearchable": "false"
}
headers = {
"Content-Type": "application/json"
}
url = f"{video_indexer_endpoint}/{video_indexer_region}/Accounts/{video_indexer_account_id}/Projects?accessToken={access_token}"
response = requests.post(url, json=data, headers=headers)
print(response.content)
if response.status_code == 200:
data = response.json()
project_id = data["id"]
return project_id
else:
return None
def render_video(access_token, project_id):
url = f"{video_indexer_endpoint}/{video_indexer_region}/Accounts/{video_indexer_account_id}/Projects/{project_id}/render?sendCompletionEmail=false&accessToken={access_token}"
headers = {
"Content-Type": "application/json"
}
response = requests.post(url, headers=headers)
print(response.content)
if response.status_code == 202:
return response
else:
return None
def get_render_operation(access_token, project_id):
url = f"{video_indexer_endpoint}/{video_indexer_region}/Accounts/{video_indexer_account_id}/Projects/{project_id}/renderoperation?accessToken={access_token}"
while True:
response = requests.get(url)
data = response.json()
if "state" in data and data['state'] == 'Succeeded':
return data
print("Sleeping for ten seconds before checking on rendering...")
time.sleep(10) # Wait 10 seconds before checking again
def download_rendered_file(access_token, project_id):
url = f"{video_indexer_endpoint}/{video_indexer_region}/Accounts/{video_indexer_account_id}/Projects/{project_id}/renderedfile/downloadurl?accessToken={access_token}"
response = requests.get(url)
if response.status_code == 200:
print(response.content)
data = response.json()
if "downloadUrl" in data:
return data["downloadUrl"]
return None
# Main workflow
# access_token = get_access_token()
insights = get_video_insights(access_token, video_id)
selected_segments = get_selected_segments(insights, 10)
project_id = video_indexer_project
if not project_id:
project_id = create_project(access_token, video_id, selected_segments)
print(project_id)
if project_id:
render_response = render_video(access_token, project_id)
print(render_response)
if render_response:
status = get_render_operation(access_token, project_id)
print(status)
download_url = download_rendered_file(access_token, project_id)
print(download_url)
"""
{'state': 'Succeeded', 'result': {'videoRanges': [{'videoId': 'lwxjba8wy3', 'range': {'start': '0:00:02.7806641', 'end': '0:00:02.8139974'}}, {'videoId': 'lwxjba8wy3', 'range': {'start': '0:00:30.1820313', 'end': '0:00:30.2153646'}}, {'videoId': 'lwxjba8wy3', 'range': {'start': '0:00:48.25', 'end': '0:00:48.2840495'}}, {'videoId': 'lwxjba8wy3', 'range': {'start': '0:00:54.5133464', 'end': '0:00:54.5466797'}}, {'videoId': 'lwxjba8wy3', 'range': {'start': '0:00:56.5806641', 'end': '0:00:56.6139974'}}, {'videoId': 'lwxjba8wy3', 'range': {'start': '0:01:15.8330078', 'end': '0:01:15.8663411'}}, {'videoId': 'lwxjba8wy3', 'range': {'start': '0:01:24.333724', 'end': '0:01:24.3670573'}}, {'videoId': 'lwxjba8wy3', 'range': {'start': '0:01:35.2317057', 'end': '0:01:35.2650391'}}, {'videoId': 'lwxjba8wy3', 'range': {'start': '0:01:41.280013', 'end': '0:01:41.3270182'}}, {'videoId': 'lwxjba8wy3', 'range': {'start': '0:01:50.4290365', 'end': '0:01:50.4623698'}}, {'videoId': 'lwxjba8wy3', 'range': {'start': '0:01:51.5296875', 'end': '0:01:51.5630208'}}, {'videoId': 'lwxjba8wy3', 'range': {'start': '0:01:56.8983724', 'end': '0:01:56.9317057'}}, {'videoId': 'lwxjba8wy3', 'range': {'start': '0:02:07.4166667', 'end': '0:02:07.45'}}, {'videoId': 'lwxjba8wy3', 'range': {'start': '0:02:21.9847005', 'end': '0:02:22.0180339'}}, {'videoId': 'lwxjba8wy3', 'range': {'start': '0:02:39.0670573', 'end': '0:02:39.1139974'}}, {'videoId': 'lwxjba8wy3', 'range': {'start': '0:02:49.449349', 'end': '0:02:49.4826823'}}, {'videoId': 'lwxjba8wy3', 'range': {'start': '0:02:58.1507161', 'end': '0:02:58.1840495'}}, {'videoId': 'lwxjba8wy3', 'range': {'start': '0:03:08.3180339', 'end': '0:03:08.3513672'}}, {'videoId': 'lwxjba8wy3', 'range': {'start': '0:03:20.4186849', 'end': '0:03:20.4520182'}}, {'videoId': 'lwxjba8wy3', 'range': {'start': '0:03:24.8433594', 'end': '0:03:24.8766927'}}, {'videoId': 'lwxjba8wy3', 'range': {'start': '0:03:27.025', 'end': '0:03:27.0583333'}}, {'videoId': 'lwxjba8wy3', 'range': {'start': '0:03:58.1970052', 'end': '0:03:58.2303385'}}, {'videoId': 'lwxjba8wy3', 'range': {'start': '0:04:13.4656901', 'end': '0:04:13.4990234'}}, {'videoId': 'lwxjba8wy3', 'range': {'start': '0:04:26.5160156', 'end': '0:04:26.549349'}}, {'videoId': 'lwxjba8wy3', 'range': {'start': '0:04:40.05', 'end': '0:04:40.0833333'}}, {'videoId': 'lwxjba8wy3', 'range': {'start': '0:04:49.764388', 'end': '0:04:49.7977214'}}, {'videoId': 'lwxjba8wy3', 'range': {'start': '0:04:58.364388', 'end': '0:04:58.3977214'}}]}, 'error': None}
b'{"downloadUrl":"https://sadronevideo.blob.core.windows.net/vi-rendered-wfmat1ysct-0e4129/wfmat1ysct_rendered.mp4?skoid=c855c9a9-c3b8-449d-b876-75304f769177&sktid=1f4c33e1-e960-43bf-a135-6db8b82b6885&skt=2025-06-25T03%3A54%3A43Z&ske=2025-07-02T03%3A54%3A43Z&sks=b&skv=2021-10-04&sv=2021-10-04&st=2025-06-27T03%3A34%3A35Z&se=2025-06-27T04%3A39%3A35Z&sr=b&sp=r&scid=942959fd-c90a-4aab-8cd8-3ab7881559b8&sig=GkzcpywilXA74afVr%2BaUtcF08Tu%2Fz5X4cS0jpGeudIA%3D"}'
Result:
https://sadronevideo.blob.core.windows.net/vi-rendered-wfmat1ysct-0e4129/wfmat1ysct_rendered.mp4?skoid=c855c9a9-c3b8-449d-b876-75304f769177&sktid=1f4c33e1-e960-43bf-a135-6db8b82b6885&skt=2025-06-25T03%3A54%3A43Z&ske=2025-07-02T03%3A54%3A43Z&sks=b&skv=2021-10-04&sv=2021-10-04&st=2025-06-27T03%3A34%3A35Z&se=2025-06-27T04%3A39%3A35Z&sr=b&sp=r&scid=942959fd-c90a-4aab-8cd8-3ab7881559b8&sig=GkzcpywilXA74afVr%2BaUtcF08Tu%2Fz5X4cS0jpGeudIA%3D
"""
#Codingexercise:
https://1drv.ms/w/c/d609fb70e39b65c8/Echlm-Nw-wkggNb7JAEAAAABu53rpIuTS5AsMb3lNiM7SQ?e=fx6G9w