Friday, June 27, 2025

 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



No comments:

Post a Comment