{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Video Codec Unit (VCU) Demo Example: STREAM_IN->DECODE ->DISPLAY "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Introduction\n",
    "\n",
    "Video Codec Unit (VCU) in ZynqMP SOC is capable of encoding and decoding AVC/HEVC compressed video streams in real time. \n",
    "\n",
    "This notebook example acts as Client pipeline in streaming use case. It needs to be run along with Server notebook (__vcu-demo-transcode-to-streamout. ipynb or vcu-demo-camera-encode-streamout. ipynb__). It receives encoded data over network, decode using VCU and render it on DP/HDMI Monitor.\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Implementation Details\n",
    "\n",
    "<img src=\"pictures/block-diagram-streamin-decode.png\" align=\"center\" alt=\"Drawing\" style=\"width: 600px; height: 200px\"/>\n",
    "\n",
    "This example requires two boards, board-1 is used for transcode and stream-out (as a server) and **board 2** is used for streaming-in and decode purpose (as a client) or VLC player on the host machine can be used as client instead of board-2 (More details regarding Test Setup for board-1 can be found in transcode → stream-out Example).\n",
    "\n",
    "__Note:__ This notebook needs to be run along with \"vcu-demo-transcode-to-streamout.ipynb\" or \"vcu-demo-camera-encode-streamout.ipynb\". The configuration settings below are for Client-side pipeline. \n",
    "\n",
    "### Board Setup\n",
    "**Board 2 is used for streaming-in and decode purpose (as a client)**\n",
    " 1. Connect 4k DP/HDMI display to board.\n",
    " 2. Connect serial cable to monitor logs on serial console.\n",
    " 3. If Board is connected to private network, then export proxy settings in /home/root/.bashrc file on board as below,\n",
    "    - create/open a bashrc file using \"vi ~/.bashrc\" \n",
    "        - Insert below line to bashrc file\n",
    "            - export http_proxy=\"< private network proxy address >\"\n",
    "            - export https_proxy=\"< private network proxy address >\"\n",
    "        - Save and close bashrc file.\n",
    " 4. Connect two boards in the same network so that they can access each other using IP address.\n",
    " 5. Check server IP on server board.\n",
    "    - root@zcu106-zynqmp:~#ifconfig\n",
    " 6. Check client IP.\n",
    " 7. Check connectivity for board-1 & board-2.\n",
    "    - root@zcu106-zynqmp:~#ping <board-2's IP>\n",
    " 8. Run stream-in → Decode on board-2\n",
    " \n",
    "Create test.sdp file on host with below content (Add separate line in test.sdp for each item below) and play test.sdp on host machine.\n",
    " 1. v=0 c=IN IP4 <Client machine IP address>\n",
    " 2. m=video 50000 RTP/AVP 96\n",
    " 3. a=rtpmap:96 H264/90000\n",
    " 4. a=framerate=30\n",
    "    \n",
    "Trouble-shoot for VLC player setup:\n",
    " 1. IP4 is client-IP address\n",
    " 2. H264/H265 is used based on received codec type on the client\n",
    " 3. Turn-off firewall in host machine if packets are not received to VLC."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<script>\n",
       "code_show=true; \n",
       "function code_toggle() {\n",
       " if (code_show){\n",
       " $('div.input').hide();\n",
       " } else {\n",
       " $('div.input').show();\n",
       " }\n",
       " code_show = !code_show\n",
       "} \n",
       "$( document ).ready(code_toggle);\n",
       "</script>\n",
       "<form action=\"javascript:code_toggle()\"><input type=\"submit\" value=\"Click here to toggle on/off the raw code.\"></form>"
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "execution_count": 1,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from IPython.display import HTML\n",
    "\n",
    "HTML('''<script>\n",
    "code_show=true; \n",
    "function code_toggle() {\n",
    " if (code_show){\n",
    " $('div.input').hide();\n",
    " } else {\n",
    " $('div.input').show();\n",
    " }\n",
    " code_show = !code_show\n",
    "} \n",
    "$( document ).ready(code_toggle);\n",
    "</script>\n",
    "<form action=\"javascript:code_toggle()\"><input type=\"submit\" value=\"Click here to toggle on/off the raw code.\"></form>''')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Run the Demo"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "from ipywidgets import interact\n",
    "import ipywidgets as widgets\n",
    "from common import common_vcu_demo_streamin_decode_display\n",
    "import os\n",
    "from ipywidgets import HBox, VBox, Text, Layout"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Video"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "5d73bfcb194449adb56e283422cd4e24",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "HBox(children=(RadioButtons(description='Codec Type:', options=('avc', 'hevc'), value='avc'), interactive(chil…"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "codec_type=widgets.RadioButtons(\n",
    "    options=['avc', 'hevc'],\n",
    "    description='Codec Type:',\n",
    "    disabled=False)\n",
    "video_sink={'kmssink':['DP', 'HDMI'], 'fakevideosink':['none']}\n",
    "\n",
    "def print_video_sink(VideoSink):\n",
    "    pass\n",
    "\n",
    "def select_video_sink(VideoCodec):\n",
    "    display_type.options = video_sink[VideoCodec]\n",
    "\n",
    "sink_name = widgets.RadioButtons(options=sorted(video_sink.keys(), key=lambda k: len(video_sink[k]), reverse=True), description='Video Sink:')\n",
    "\n",
    "init = sink_name.value\n",
    "\n",
    "display_type = widgets.RadioButtons(options=video_sink[init], description='Display:')\n",
    "j = widgets.interactive(print_video_sink, VideoSink=display_type)\n",
    "i = widgets.interactive(select_video_sink, VideoCodec=sink_name)\n",
    "\n",
    "HBox([codec_type, i, j])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Audio"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "5431b9e2cde94da4a6c1e5c06d214cf1",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "HBox(children=(interactive(children=(RadioButtons(description='Audio Codec:', options=('none', 'vorbis', 'aac'…"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "audio_sink={'none':['none'], 'aac':['auto','alsasink','pulsesink'],'vorbis':['auto','alsasink','pulsesink']}\n",
    "audio_src={'none':['none'], 'aac':['auto','alsasrc','pulsesrc'],'vorbis':['auto','alsasrc','pulsesrc']}\n",
    "\n",
    "#val=sorted(audio_sink, key = lambda k: (-len(audio_sink[k]), k))\n",
    "def print_audio_sink(AudioSink):\n",
    "    pass\n",
    "    \n",
    "def print_audio_src(AudioSrc):\n",
    "    pass\n",
    "\n",
    "def select_audio_sink(AudioCodec):\n",
    "    audio_sinkW.options = audio_sink[AudioCodec]\n",
    "    audio_srcW.options = audio_src[AudioCodec]\n",
    "\n",
    "audio_codecW = widgets.RadioButtons(options=sorted(audio_sink.keys(), key=lambda k: len(audio_sink[k])), description='Audio Codec:')\n",
    "\n",
    "init = audio_codecW.value\n",
    "\n",
    "audio_sinkW = widgets.RadioButtons(options=audio_sink[init], description='Audio Sink:')\n",
    "audio_srcW = widgets.RadioButtons(options=audio_src[init], description='Audio Src:')\n",
    "j = widgets.interactive(print_audio_sink, AudioSink=audio_sinkW)\n",
    "i = widgets.interactive(select_audio_sink, AudioCodec=audio_codecW)\n",
    "\n",
    "HBox([i, j])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Advanced options:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "6e9e3af6b7e7481aafbb186db7cc7429",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "HBox(children=(Text(value='', description='Kernel Recv Buf Size:', placeholder='(optional) 16000000', style=De…"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "kernel_recv_buffer_size=widgets.Text(value='',\n",
    "    placeholder='(optional) 16000000',\n",
    "    description='Kernel Recv Buf Size:',\n",
    "    style={'description_width': 'initial'},\n",
    "    #layout=Layout(width='33%', height='30px'),\n",
    "    disabled=False)\n",
    "port_number=widgets.Text(value='',\n",
    "    placeholder='(optional) 50000, 42000',\n",
    "    description=r'Port No:',\n",
    "    #style={'description_width': 'initial'},\n",
    "    #\n",
    "    disabled=False)\n",
    "#kernel_recv_buffer_size\n",
    "HBox([kernel_recv_buffer_size, port_number])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "d9c1cc754ddc4ba5b4c4187cf72c7766",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "HBox(children=(Dropdown(description='Entropy Buffers Nos:', index=3, options=('2', '3', '4', '5', '6', '7', '8…"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "entropy_buffers=widgets.Dropdown(\n",
    "    options=['2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12', '13', '14', '15'],\n",
    "    value='5',\n",
    "    description='Entropy Buffers Nos:',\n",
    "    style={'description_width': 'initial'},\n",
    "    disabled=False,)\n",
    "show_fps=widgets.Checkbox(\n",
    "    value=False,\n",
    "    description='show-fps',\n",
    "    #style={'description_width': 'initial'},\n",
    "    disabled=False)\n",
    "HBox([entropy_buffers, show_fps])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [],
   "source": [
    "from IPython.display import clear_output\n",
    "from IPython.display import Javascript\n",
    "\n",
    "def run_all(ev):\n",
    "    display(Javascript('IPython.notebook.execute_cells_below()'))\n",
    "\n",
    "def clear_op(event):\n",
    "    clear_output(wait=True)\n",
    "    return\n",
    "\n",
    "button1 = widgets.Button(\n",
    "    description='Clear Output',\n",
    "    style= {'button_color':'lightgreen'},\n",
    "    #style= {'button_color':'lightgreen', 'description_width': 'initial'},\n",
    "    layout={'width': '300px'}\n",
    ")\n",
    "button2 = widgets.Button(\n",
    "    description='',\n",
    "    style= {'button_color':'white'},\n",
    "    #style= {'button_color':'lightgreen', 'description_width': 'initial'},\n",
    "    layout={'width': '38px'},\n",
    "    disabled=True\n",
    ")\n",
    "button1.on_click(run_all)\n",
    "button1.on_click(clear_op)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "16ed3f98945948008c6935c65ca0d7d1",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "HBox(children=(Button(description='click to start vcu-stream_in-decode-display demo', layout=Layout(width='350…"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "def start_demo(event):\n",
    "    #clear_output(wait=True)\n",
    "    arg = common_vcu_demo_streamin_decode_display.cmd_line_args_generator(port_number.value, codec_type.value, audio_codecW.value, display_type.value, kernel_recv_buffer_size.value, sink_name.value, entropy_buffers.value, show_fps.value, audio_sinkW.value);\n",
    "    #sh vcu-demo-streamin-decode-display.sh $arg > logs.txt 2>&1\n",
    "    !sh vcu-demo-streamin-decode-display.sh $arg\n",
    "    return\n",
    "\n",
    "button = widgets.Button(\n",
    "    description='click to start vcu-stream_in-decode-display demo',\n",
    "    style= {'button_color':'lightgreen'},\n",
    "    #style= {'button_color':'lightgreen', 'description_width': 'initial'},\n",
    "    layout={'width': '350px'}\n",
    ")\n",
    "button.on_click(start_demo)\n",
    "HBox([button, button2, button1])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# References\n",
    "[1] https://xilinx-wiki.atlassian.net/wiki/spaces/A/pages/18842546/Xilinx+Video+Codec+Unit\n",
    "\n",
    "[2] https://www.xilinx.com/support.html#documentation (Refer to PG252)"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "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.5.6"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
