Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding videodecode Jupyter's notebook sample #131

Open
wants to merge 2 commits into
base: develop
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
391 changes: 391 additions & 0 deletions samples/jupyter_notebooks/videodecode.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,391 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"[![MIT licensed](https://img.shields.io/badge/license-MIT-blue.svg)](https://opensource.org/licenses/MIT)\n",
"\n",
"# rocPyDecode \n",
"##### rocDecode Python Binding\n",
"\n",
"> **NOTE**\n",
"> The published documentation is available at [rocPyDecode](https://rocm.docs.amd.com/projects/rocPyDecode/en/latest/index.html) in an organized, easy-to-read format, with search and a table of contents. The documentation source files reside in the `docs` folder of this repository. As with all ROCm projects, the documentation is open source. For more information on contributing to the documentation, see [Contribute to ROCm documentation](https://rocm.docs.amd.com/en/latest/contribute/contributing.html).\n",
"\n",
"\n",
"The rocDecode Python Binding, rocPyDecode, is a tool that allows users to access rocDecode APIs in both Python and C/C++ languages. It works by connecting Python and C/C++ libraries, enabling function calling and data passing between the two languages. The rocpydecode.so library is a wrapper that facilitates the use of rocDecode APIs that are written primarily in C/C++ language within Python.\n",
"\n",
"## Prerequisites\n",
"\n",
"* Linux distribution\n",
" * Ubuntu - `20.04` / `22.04`\n",
"\n",
"* [ROCm-supported hardware](https://rocm.docs.amd.com/projects/install-on-linux/en/latest/reference/system-requirements.html)\n",
"> **IMPORTANT**\n",
"> `gfx908` or higher GPU required\n",
"\n",
"* Install ROCm `6.2.0` or later with [amdgpu-install](https://rocm.docs.amd.com/projects/install-on-linux/en/latest/how-to/amdgpu-install.html): Required usecase - rocm\n",
"> **IMPORTANT**\n",
"> `sudo amdgpu-install --usecase=rocm`"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Video Decode Python Sample"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Import rocPyDecode Modules"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import pyRocVideoDecode.decoder as dec\n",
"import pyRocVideoDecode.demuxer as dmx"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"##### Other needed modules"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import datetime\n",
"import sys\n",
"import argparse\n",
"import os.path"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Construct Demuxer & Decoder Instances "
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"<i>Set parameters to construct demuxer and decoder instance</i>"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"input_file_path = \"../../data/videos/AMD_driving_virtual_20-H265.mp4\" # must be set to valid video existing video file\n",
"output_file_path = None\n",
"device_id = 0\n",
"mem_type = 0 \n",
"b_force_zero_latency = False\n",
"crop_rect = None\n",
"b_generate_md5 = False\n",
"ref_md5_file = None\n",
"seek_frame = -1\n",
"seek_mode = 1\n",
"seek_criteria = 0\n",
"resize_dim = None"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### Instantiate demuxer and decoder"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# demuxer instance\n",
"demuxer = dmx.demuxer(input_file_path)\n",
"\n",
"# get the used coded id\n",
"codec_id = dec.GetRocDecCodecID(demuxer.GetCodecId())\n",
"\n",
"# decoder instance\n",
"viddec = dec.decoder(\n",
" codec_id,\n",
" device_id,\n",
" mem_type,\n",
" b_force_zero_latency,\n",
" crop_rect,\n",
" 0,\n",
" 0,\n",
" 1000)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"<i>Check if codec of the input video is supported</i>"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Get GPU device information\n",
"cfg = viddec.GetGpuInfo()\n",
"\n",
"# check if codec is supported\n",
"if (viddec.IsCodecSupported(device_id, codec_id, demuxer.GetBitDepth()) == False):\n",
" print(\"ERROR: Codec is not supported on this GPU \" + cfg.device_name)\n",
" exit()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"<i>Printout system/env information</i>"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# print some GPU info out\n",
"print(\"\\ninfo: Input file: \" + \n",
" input_file_path + '\\n' + \"info: Using GPU device \" + str(device_id) + \" - \" +\n",
" cfg.device_name + \"[\" + cfg.gcn_arch_name + \"] on PCI bus \" + str(cfg.pci_bus_id) +\n",
" \":\" + str(cfg.pci_domain_id) + \".\" + str(cfg.pci_device_id))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Setup MD5 if requested"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# md5 file full path & md5 flag\n",
"b_md5_check = False\n",
"if (ref_md5_file is not None):\n",
" if os.path.exists(ref_md5_file):\n",
" b_generate_md5 = True\n",
" b_md5_check = True\n",
"\n",
"# init MD5 if requested\n",
"if b_generate_md5:\n",
" viddec.InitMd5()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"<i> Set reconfiguration params</i>"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# set reconfiguration params based on user arguments\n",
"flush_mode = 0\n",
"if (output_file_path is not None):\n",
" flush_mode = 1\n",
"elif b_generate_md5:\n",
" flush_mode = 2\n",
"viddec.SetReconfigParams(flush_mode, output_file_path if (output_file_path is not None) else str(\"\"))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Start the decoding loop"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Setup vars for the decoding loop\n",
"n_frame = 0\n",
"total_dec_time = 0.0\n",
"frame_is_resized = False\n",
"not_seeking = True if (seek_frame == -1) else False\n",
"session_id = 0\n",
"if (resize_dim is not None):\n",
" resize_dim = None if(resize_dim[0] == 0 or resize_dim[1] == 0) else resize_dim\n",
"\n",
"# start decoding \n",
"print(\"info: decoding started, please wait! \\n\") \n",
" \n",
"while True:\n",
" start_time = datetime.datetime.now()\n",
" if(not_seeking):\n",
" packet = demuxer.DemuxFrame()\n",
" else:\n",
" packet = demuxer.SeekFrame(seek_frame, seek_mode, seek_criteria)\n",
" not_seeking = True\n",
" n_frame_returned = viddec.DecodeFrame(packet)\n",
" for i in range(n_frame_returned):\n",
" viddec.GetFrameYuv(packet)\n",
" if (b_generate_md5):\n",
" surface_info = viddec.GetOutputSurfaceInfo()\n",
" viddec.UpdateMd5ForFrame(packet.frame_adrs, surface_info)\n",
" if (resize_dim is not None):\n",
" surface_info = viddec.GetOutputSurfaceInfo()\n",
" if(viddec.ResizeFrame(packet, resize_dim, surface_info) != 0):\n",
" frame_is_resized = True\n",
" else:\n",
" frame_is_resized = False\n",
" if (output_file_path is not None):\n",
" if (frame_is_resized):\n",
" resized_surface_info = viddec.GetResizedOutputSurfaceInfo()\n",
" viddec.SaveFrameToFile(output_file_path, packet.frame_adrs_resized, resized_surface_info)\n",
" else:\n",
" viddec.SaveFrameToFile(output_file_path, packet.frame_adrs)\n",
"\n",
" # release frame\n",
" viddec.ReleaseFrame(packet)\n",
"\n",
" # measure after completing a whole frame\n",
" end_time = datetime.datetime.now()\n",
" time_per_frame = end_time - start_time\n",
" total_dec_time = total_dec_time + time_per_frame.total_seconds()\n",
"\n",
" # increament frames counter\n",
" n_frame += n_frame_returned\n",
" if (packet.bitstream_size <= 0): # EOF: no more to decode\n",
" break\n",
" \n",
"# decoding end\n",
"print(\"info: decoding ended! \\n\") "
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Beyond the decoding loop"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"<i>Calculate overhead and FPS</i>"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# after the decoding loop\n",
"n_frame += viddec.GetNumOfFlushedFrames()\n",
"print(\"info: Total frame decoded: \" + str(n_frame))\n",
"\n",
"# Calculate if overhead\n",
"if (output_file_path is None):\n",
" if (n_frame > 0 and total_dec_time > 0):\n",
" time_per_frame = (total_dec_time / n_frame) * 1000\n",
" session_overhead = viddec.GetDecoderSessionOverHead(session_id)\n",
" if (session_overhead == None):\n",
" session_overhead = 0\n",
" time_per_frame -= (session_overhead / n_frame) # remove the overhead\n",
" frame_per_second = n_frame / total_dec_time\n",
" print(\"info: avg decoding time per frame: \" +\"{0:0.2f}\".format(round(time_per_frame, 2)) + \" ms\")\n",
" print(\"info: avg frame per second: \" +\"{0:0.2f}\".format(round(frame_per_second,2)) +\"\\n\")\n",
" else:\n",
" print(\"info: frame count= \", n_frame)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"<i> MD5-Digest if requested</i>"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# if MD5 check requested\n",
"if b_generate_md5:\n",
" digest = viddec.FinalizeMd5()\n",
" print(\"MD5 message digest: \", end=\" \")\n",
" str_digest = \"\"\n",
" for i in range(16):\n",
" str_digest = str_digest + str(format('%02x' % int(digest[i])))\n",
" print(str_digest)\n",
" if (b_md5_check):\n",
" f = open(ref_md5_file)\n",
" md5_from_file = f.read(16 * 2)\n",
" b_match = (md5_from_file == str_digest)\n",
" if (b_match):\n",
" print(\"MD5 digest matches the reference MD5 digest.\\n\")\n",
" else:\n",
" print(\n",
" \"MD5 digest does not match the reference MD5 digest: \",\n",
" md5_from_file)"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.10.12"
}
},
"nbformat": 4,
"nbformat_minor": 2
}
Loading