From fea4d3574270f5e817ebe44cc326b58aa758580c Mon Sep 17 00:00:00 2001
From: Sunny Shukla <sunny.shukla@einfochips.com>
Date: Thu, 15 Dec 2016 01:58:58 +0530
Subject: [PATCH] Input format NV12 Tile support added

NV12 Tile format conversion to NV12 and yuv420p
support is added. NV12 Tile format conversion
support is only for as input format not
as output format.

Signed-off-by: Sunny Shukla <sunny.shukla@einfochips.com>
---
 Changelog                     |   1 +
 libavutil/Makefile            |   4 +
 libavutil/imgutils.c          |  14 ++-
 libavutil/pixdesc.c           |  12 +++
 libavutil/pixfmt.h            |   1 +
 libavutil/special_format.c    |  60 ++++++++++++
 libavutil/special_format.h    |  75 +++++++++++++++
 libavutil/utils.c             |   2 +-
 libswscale/Makefile           |   2 +
 libswscale/nv12tiled2nv12.c   | 212 ++++++++++++++++++++++++++++++++++++++++++
 libswscale/nv12tiled2nv12.h   |  85 +++++++++++++++++
 libswscale/swscale_internal.h |   5 +
 libswscale/swscale_unscaled.c |  54 ++++++++++-
 libswscale/utils.c            |  19 ++++
 14 files changed, 541 insertions(+), 5 deletions(-)
 create mode 100644 libavutil/special_format.c
 create mode 100644 libavutil/special_format.h
 create mode 100644 libswscale/nv12tiled2nv12.c
 create mode 100644 libswscale/nv12tiled2nv12.h

diff --git a/Changelog b/Changelog
index b36a631..23a3d87 100644
--- a/Changelog
+++ b/Changelog
@@ -9,6 +9,7 @@ version <next>:
 - Support for spherical videos
 - configure now fails if autodetect-libraries are requested but not found
 - PSD Decoder
+- Input format NV12 Tile support added
 
 version 3.2:
 - libopenmpt demuxer
diff --git a/libavutil/Makefile b/libavutil/Makefile
index 9841645..5d29663 100644
--- a/libavutil/Makefile
+++ b/libavutil/Makefile
@@ -74,6 +74,8 @@ HEADERS = adler32.h                                                     \
           version.h                                                     \
           xtea.h                                                        \
           tea.h                                                         \
+          special_format.h												\
+
 
 HEADERS-$(CONFIG_LZO)                   += lzo.h
 
@@ -152,6 +154,8 @@ OBJS = adler32.o                                                        \
        xga_font_data.o                                                  \
        xtea.o                                                           \
        tea.o                                                            \
+       special_format.o                                                 \
+
 
 OBJS-$(!HAVE_ATOMICS_NATIVE)            += atomic.o                     \
 
diff --git a/libavutil/imgutils.c b/libavutil/imgutils.c
index cc410ab..426b20c 100644
--- a/libavutil/imgutils.c
+++ b/libavutil/imgutils.c
@@ -30,6 +30,7 @@
 #include "mathematics.h"
 #include "pixdesc.h"
 #include "rational.h"
+#include "special_format.h"
 
 void av_image_fill_max_pixsteps(int max_pixsteps[4], int max_pixstep_comps[4],
                                 const AVPixFmtDescriptor *pixdesc)
@@ -119,9 +120,14 @@ int av_image_fill_pointers(uint8_t *data[4], enum AVPixelFormat pix_fmt, int hei
         return AVERROR(EINVAL);
 
     data[0] = ptr;
+
     if (linesizes[0] > (INT_MAX - 1024) / height)
         return AVERROR(EINVAL);
-    size[0] = linesizes[0] * height;
+
+    if(pix_fmt == AV_PIX_FMT_NV12_TILED)
+        size[0] = avpriv_nv12tile_calc_plane_size(linesizes[0],height);
+    else
+        size[0] = linesizes[0] * height;
 
     if (desc->flags & AV_PIX_FMT_FLAG_PAL ||
         desc->flags & AV_PIX_FMT_FLAG_PSEUDOPAL) {
@@ -139,7 +145,11 @@ int av_image_fill_pointers(uint8_t *data[4], enum AVPixelFormat pix_fmt, int hei
         h = (height + (1 << s) - 1) >> s;
         if (linesizes[i] > INT_MAX / h)
             return AVERROR(EINVAL);
-        size[i] = h * linesizes[i];
+
+        if(pix_fmt == AV_PIX_FMT_NV12_TILED)
+            size[i] = avpriv_nv12tile_calc_plane_size(linesizes[i],h);
+        else
+            size[i] = h * linesizes[i];
         if (total_size > INT_MAX - size[i])
             return AVERROR(EINVAL);
         total_size += size[i];
diff --git a/libavutil/pixdesc.c b/libavutil/pixdesc.c
index 3b9c45d..64b641a 100644
--- a/libavutil/pixdesc.c
+++ b/libavutil/pixdesc.c
@@ -448,6 +448,18 @@ static const AVPixFmtDescriptor av_pix_fmt_descriptors[AV_PIX_FMT_NB] = {
         },
         .flags = AV_PIX_FMT_FLAG_PLANAR,
     },
+    [AV_PIX_FMT_NV12_TILED] = {
+        .name = "nv12_tiled",
+        .nb_components = 3,
+        .log2_chroma_w = 1,
+        .log2_chroma_h = 1,
+        .comp = {
+            { 0, 1, 0, 0, 8, 0, 7, 1 },        /* Y */
+            { 1, 2, 0, 0, 8, 1, 7, 1 },        /* U */
+            { 1, 2, 1, 0, 8, 1, 7, 2 },        /* V */
+        },
+        .flags = AV_PIX_FMT_FLAG_PLANAR,
+    },
     [AV_PIX_FMT_NV21] = {
         .name = "nv21",
         .nb_components = 3,
diff --git a/libavutil/pixfmt.h b/libavutil/pixfmt.h
index dfb1b11..d18d463 100644
--- a/libavutil/pixfmt.h
+++ b/libavutil/pixfmt.h
@@ -88,6 +88,7 @@ enum AVPixelFormat {
     AV_PIX_FMT_RGB4,      ///< packed RGB 1:2:1 bitstream,  4bpp, (msb)1R 2G 1B(lsb), a byte contains two pixels, the first pixel in the byte is the one composed by the 4 msb bits
     AV_PIX_FMT_RGB4_BYTE, ///< packed RGB 1:2:1,  8bpp, (msb)1R 2G 1B(lsb)
     AV_PIX_FMT_NV12,      ///< planar YUV 4:2:0, 12bpp, 1 plane for Y and 1 plane for the UV components, which are interleaved (first byte U and the following byte V)
+    AV_PIX_FMT_NV12_TILED,///< same as NV12, but frame data is divided in microblocks/tiles having size 64*32, follows Z and flip Z pattern in logical memory layout
     AV_PIX_FMT_NV21,      ///< as above, but U and V bytes are swapped
 
     AV_PIX_FMT_ARGB,      ///< packed ARGB 8:8:8:8, 32bpp, ARGBARGB...
diff --git a/libavutil/special_format.c b/libavutil/special_format.c
new file mode 100644
index 0000000..8b7a3f2
--- /dev/null
+++ b/libavutil/special_format.c
@@ -0,0 +1,60 @@
+/*
+ * NV12 tiled format support.
+ * Copyright (C) 2016 eInfochips India Pvt. Ltd.
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+#include "special_format.h"
+
+uint32_t avpriv_nv12tile_calc_wTiles(uint32_t width)
+{
+    return (ROUND_UP_X(width,128)/64);
+}
+
+uint32_t avpriv_nv12tile_calc_hTiles(uint32_t height)
+{
+    return (ROUND_UP_X(height,32)/32);
+}
+
+uint32_t avpriv_nv12tile_calc_boundary_padding(uint32_t width,uint32_t height)
+{
+    uint32_t wTiles = 0;
+    uint32_t hTiles = 0;
+    float data_size = 0;
+    uint32_t padding = 0;
+
+    wTiles = avpriv_nv12tile_calc_wTiles(width);
+    hTiles = avpriv_nv12tile_calc_hTiles(height);
+
+    data_size = ((float)((float)(((float)wTiles * (float)hTiles
+                        * (float)NV12_TILE_SIZE)/(float)(4 * NV12_TILE_SIZE))));
+
+	data_size = data_size - (float)((uint32_t)data_size);
+
+    padding = (uint32_t)(data_size * (float)(4 * NV12_TILE_SIZE));
+
+    return padding;
+}
+
+uint32_t avpriv_nv12tile_calc_plane_size(uint32_t width,uint32_t height)
+{
+    if((0 == width) || (0 == height))
+        return 0;
+
+    return ((NV12_TILE_SIZE * avpriv_nv12tile_calc_wTiles(width) * avpriv_nv12tile_calc_hTiles(height))
+            + avpriv_nv12tile_calc_boundary_padding(width,height));
+}
diff --git a/libavutil/special_format.h b/libavutil/special_format.h
new file mode 100644
index 0000000..bde8f78
--- /dev/null
+++ b/libavutil/special_format.h
@@ -0,0 +1,75 @@
+/*
+ * NV12 tiled format support.
+ * Copyright (C) 2016 eInfochips India Pvt. Ltd.
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef AVUTIL_SPECIAL_FORMAT_H
+#define AVUTIL_SPECIAL_FORMAT_H
+#include <stdint.h>
+
+//NOTE : This NV12Tile to NV12 conversion is taken from "https://github.com/ssshukla26/NV12Tile-To-NV12-Conversion" repo.
+
+/**
+ * Macro to round up a number "num" to the given number "X"
+ */
+#define ROUND_UP_X(num,x) (((num)+(x-1))&~(x-1))
+
+/**
+ * Size of a single tile
+ */
+#define NV12_TILE_SIZE (64*32)
+
+/**
+ * This function returns no of tiles required
+ * for given width.
+ *
+ * @param width - width of the resolution
+ * @return no. of vertical tiles with respect to the width
+ */
+uint32_t avpriv_nv12tile_calc_wTiles(uint32_t width);
+
+/**
+ * This function returns no of tiles required
+ * for given height.
+ *
+ * @param height - height of the resolution
+ * @return no. of horizontal tiles with respect to height
+ */
+uint32_t avpriv_nv12tile_calc_hTiles(uint32_t height);
+
+/**
+ * This function will return padding required for
+ * a buffer made out of wTiles and hTiles.
+ *
+ * @param wTiles - no. of vertical tiles
+ * @param hTiles - no. of horizontal tiles
+ * @return boundary padding required with respect to horizontal and vertical tiles
+ */
+uint32_t avpriv_nv12tile_calc_boundary_padding(uint32_t width,uint32_t height);
+
+/**
+ * This function will returns size required
+ * for a plane of given width and height.
+ *
+ * @param width - width of the resolution
+ * @param height - height of the resolution
+ * @return plane size required with respect to width and height
+ */
+uint32_t avpriv_nv12tile_calc_plane_size(uint32_t width,uint32_t height);
+#endif
diff --git a/libavutil/utils.c b/libavutil/utils.c
index 36e4dd5..e408eba 100644
--- a/libavutil/utils.c
+++ b/libavutil/utils.c
@@ -42,7 +42,7 @@ unsigned avutil_version(void)
         return LIBAVUTIL_VERSION_INT;
 
 #if FF_API_VDPAU
-    av_assert0(AV_PIX_FMT_VDA_VLD == 81); //check if the pix fmt enum has not had anything inserted or removed by mistake
+    av_assert0(AV_PIX_FMT_VDA_VLD == 82); //check if the pix fmt enum has not had anything inserted or removed by mistake
 #endif
     av_assert0(AV_SAMPLE_FMT_DBLP == 9);
     av_assert0(AVMEDIA_TYPE_ATTACHMENT == 4);
diff --git a/libswscale/Makefile b/libswscale/Makefile
index 0272039..ecd6dc4 100644
--- a/libswscale/Makefile
+++ b/libswscale/Makefile
@@ -19,6 +19,8 @@ OBJS = alphablend.o                                     \
        utils.o                                          \
        yuv2rgb.o                                        \
        vscale.o                                         \
+	   nv12tiled2nv12.o                                 \
+	   ../libavutil/special_format.o                    \
 
 OBJS-$(CONFIG_SHARED)        += log2_tab.o
 
diff --git a/libswscale/nv12tiled2nv12.c b/libswscale/nv12tiled2nv12.c
new file mode 100644
index 0000000..f949b44
--- /dev/null
+++ b/libswscale/nv12tiled2nv12.c
@@ -0,0 +1,212 @@
+/*
+ * NV12 tiled to NV12 conversion support.
+ * Copyright (C) 2016 eInfochips India Pvt. Ltd.
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+#include "libavutil/mem.h"
+#include "libavutil/special_format.h"
+#include "nv12tiled2nv12.h"
+
+//This functions copy a single tile from source to destination
+static void nv12tile_copy_tile(uint8_t *dst,uint8_t **src,uint32_t wTiles);
+
+struct nv12TileParams *ff_nv12tile_params_init(uint32_t width, uint32_t height)
+{
+    struct nv12TileParams *params = NULL;
+
+    if(NULL == (params = (struct nv12TileParams *) av_mallocz(sizeof(struct nv12TileParams))))
+        goto error;
+
+    params->width = width;
+    params->height = height;
+
+    //Extrapolate width
+    width = ROUND_UP_X(width,128);
+
+    params->wTiles = avpriv_nv12tile_calc_wTiles(width);
+    params->hTiles = avpriv_nv12tile_calc_hTiles(height);
+    params->hTiles_UV = avpriv_nv12tile_calc_hTiles(height/2);
+
+    params->frame_size_src_Y = avpriv_nv12tile_calc_plane_size(width,height);
+    params->frame_size_src_UV = avpriv_nv12tile_calc_plane_size(width,height/2);
+
+    if((params->frame_size_src_Y <= 0) || (params->frame_size_src_UV <= 0))
+        goto error;
+
+    if(NULL == (params->t_dst[0] = (uint8_t *) av_mallocz((params->frame_size_src_Y + params->frame_size_src_UV) * sizeof(uint8_t))))
+        goto error;
+    else
+        params->t_dst[1] = params->t_dst[0] + (params->frame_size_src_Y * sizeof(uint8_t));
+
+    return params;
+
+error:
+    ff_nv12tile_params_deinit(params);
+
+    return NULL;
+}
+
+void ff_nv12tile_params_deinit(struct nv12TileParams *params)
+{
+    if(params) {
+
+        if(params->t_dst[0]) {
+
+            av_free(params->t_dst[0]);
+            params->t_dst[0] = NULL;
+            params->t_dst[1] = NULL;
+        }
+
+        av_free(params);
+    }
+}
+
+static void nv12tile_copy_tile(uint8_t *dst,uint8_t **src,uint32_t wTiles)
+{
+    //Loop variable
+    uint32_t loop = 0;
+
+    //Run loop for all rows in a tile i.e. from row 0 to row 31
+    for(loop=0;loop<32;loop++) {
+
+        //Copy a single row from source to destination
+        memcpy(dst,*src,64 * sizeof(uint8_t));
+
+        //Move source pointer to next row
+        *src = *src + 64;
+
+        //Move destination pointer to next row
+        dst = dst + (wTiles * 64);
+    }
+}
+
+void ff_nv12tile_to_nv12(uint8_t* dst_head,uint8_t* src_head,uint32_t wTiles,uint32_t hTiles)
+{
+    //Loop variable
+    uint32_t loop = 0;
+
+    //For Z Flip Z pattern
+    uint32_t Z = 0;
+
+    //Assign source to source head pointer
+    uint8_t *src = src_head;
+
+    //Assign destination to destination head pointer
+    uint8_t *dst = dst_head;
+
+    //For a proper Z Flip Z pattern two consecutive row are needed to be processed
+    for(loop = 0; loop < (hTiles%2 == 0 ? hTiles : hTiles-1); loop=loop+2) {
+
+        //Put src pointer at start of current row
+        src = src_head;
+
+        //Copy Z and flip Z pattern to destination
+        for(Z = 0; Z < (wTiles/2); Z++) {
+
+            //Put dst pointer at start of current row
+            dst = dst_head;
+
+            if(Z%2 == 0) {
+
+                //For Z pattern
+
+                //Tile Nos: 0-8-16-...
+                dst = dst + (Z * 2 * 64);
+                nv12tile_copy_tile(dst,&src,wTiles);
+
+                //Tile Nos: 1-9-17-...
+                dst = dst + 64;
+                nv12tile_copy_tile(dst,&src,wTiles);
+
+                //Tile Nos: 2-10-18-...
+                dst = dst_head + (wTiles * NV12_TILE_SIZE);
+                dst = dst + (Z * 2 * 64);
+                nv12tile_copy_tile(dst,&src,wTiles);
+
+                //Tile Nos: 3-11-19-...
+                dst = dst + 64;
+                nv12tile_copy_tile(dst,&src,wTiles);
+            }
+            else {
+
+                //For Flip Z pattern
+
+                //Tile Nos: 4-12-...
+                dst = dst_head + (wTiles * NV12_TILE_SIZE);
+                dst = dst + (Z * 2 * 64);
+                nv12tile_copy_tile(dst,&src,wTiles);
+
+                //Tile Nos: 5-13...
+                dst = dst + 64;
+                nv12tile_copy_tile(dst,&src,wTiles);
+
+                //Tile Nos: 6-14-...
+                dst = dst_head + (Z * 2 * 64);
+                nv12tile_copy_tile(dst,&src,wTiles);
+
+                //Tile Nos: 7-15-...
+                dst = dst + 64;
+                nv12tile_copy_tile(dst,&src,wTiles);
+            }
+        }
+
+        //Move source pointer by two chunk rows
+        src_head = src_head + (2 * NV12_TILE_SIZE * wTiles);
+
+        //Move destination pointer by two chunk rows
+        dst_head  = dst_head + (2 * wTiles * NV12_TILE_SIZE);
+    }
+
+    //For linear pattern in the last remaining row
+    if(hTiles%2) {
+
+        //Put src pointer at start of current row
+        src = src_head;
+
+        //Loop through linear tiles
+        for(loop = 0; loop < wTiles ; loop++) {
+
+            dst = dst_head + (loop * 64);
+            nv12tile_copy_tile(dst,&src,wTiles);
+        }
+    }
+}
+
+void ff_nv12tile_rectify_extrapolation(uint8_t *data, int width, int height)
+{
+    //Check if width is not equal to extrapolated width
+    //then perform the conversion
+    if(width != ROUND_UP_X(width,128)) {
+
+        //Index of current row
+        int index = 0;
+
+        //Extrapolated width of data buffer
+        int extrapolated_width = ROUND_UP_X(width,128);
+
+        //Convert extrapolated NV12 data to actual NV12 data
+        while(index <= height) {
+
+            //Rectify each strides in data buffer containing extrapolated NV12 data
+            //such that each stride will contain actual NV12 data
+            memcpy(data + (index * width), data + (index * extrapolated_width), (width * sizeof(uint8_t)));
+
+            index++;
+        }
+    }
+}
diff --git a/libswscale/nv12tiled2nv12.h b/libswscale/nv12tiled2nv12.h
new file mode 100644
index 0000000..3f72d71
--- /dev/null
+++ b/libswscale/nv12tiled2nv12.h
@@ -0,0 +1,85 @@
+/*
+ * NV12 tiled to NV12 conversion support.
+ * Copyright (C) 2016 eInfochips India Pvt. Ltd.
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef SWSCALE_NV12TILED2NV12_H
+#define SWSCALE_NV12TILED2NV12_H
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdint.h>
+
+//NOTE : This NV12Tile to NV12 conversion is taken from "https://github.com/ssshukla26/NV12Tile-To-NV12-Conversion" repo.
+
+/**
+ * Structure holding NV12 tile format specific parameters
+ */
+struct nv12TileParams {
+    uint32_t width;                 //Width of resolution
+    uint32_t height;                //Height of resolution
+    uint32_t wTiles;                //No. of vertical tiles
+    uint32_t hTiles;                //No. of horizontal tiles for Y-Plane
+    uint32_t hTiles_UV;             //No. of horizontal tiles for UV-Plane
+    uint32_t frame_size_src_Y;      //Frame size of Y-Plane
+    uint32_t frame_size_src_UV;     //Frame size of UV-Plane
+    uint8_t *t_dst[2];              //Pointer to Y and UV Plane
+};
+
+/**
+ * Function to calculate and fill nv12 tile format specific data.
+ *
+ * @param width - width of the resolution
+ * @param height - height of the resolution
+ * @return pointer to nv12TileParams
+ */
+struct nv12TileParams *ff_nv12tile_params_init(uint32_t width, uint32_t height);
+
+/**
+ * Function to free initialized parameter and data.
+ *
+ * @param params - pointer to nv12TileParams
+ * @return void
+ */
+void ff_nv12tile_params_deinit(struct nv12TileParams *params);
+
+/**
+ * This function is use to convert data from NV12tile format
+ * to NV12 format.
+ *
+ * @param dst_head - destination pointer to store data in NV12 format
+ * @param src_head - source pointer, pointing to a data in NV12tile format
+ * @param wTiles - No of horizontal tiles
+ * @param hTiles - No of vertical tiles
+ * @return void
+ */
+void ff_nv12tile_to_nv12(uint8_t* dst_head,uint8_t* src_head,uint32_t wTiles,uint32_t hTiles);
+
+/**
+ * This function is use to convert/rectify extrapolated nv12 data in a buffer
+ * to actual nv12 data.
+ *
+ * @param data      :- Pointer pointing to a extrapolated nv12 data buffer
+ * @param width     :- Actual width of data in data buffer
+ * @param height    :- Height of data buffer
+ * @return void
+ */
+void ff_nv12tile_rectify_extrapolation(uint8_t *data, int width, int height);
+#endif
diff --git a/libswscale/swscale_internal.h b/libswscale/swscale_internal.h
index af82396..81c8b8b 100644
--- a/libswscale/swscale_internal.h
+++ b/libswscale/swscale_internal.h
@@ -627,6 +627,11 @@ typedef struct SwsContext {
     SwsDither dither;
 
     SwsAlphaBlend alphablend;
+
+    /// Pointer to hold special format specific data. As of now used to store
+    /// NV12 tile format specific data.
+    void *special_format;
+
 } SwsContext;
 //FIXME check init (where 0)
 
diff --git a/libswscale/swscale_unscaled.c b/libswscale/swscale_unscaled.c
index b2bfc40..9b678d6 100644
--- a/libswscale/swscale_unscaled.c
+++ b/libswscale/swscale_unscaled.c
@@ -34,6 +34,7 @@
 #include "libavutil/pixdesc.h"
 #include "libavutil/avassert.h"
 #include "libavutil/avconfig.h"
+#include "nv12tiled2nv12.h"
 
 DECLARE_ALIGNED(8, static const uint8_t, dithers)[8][8][8]={
 {
@@ -288,6 +289,49 @@ static int planar8ToP01xleWrapper(SwsContext *c, const uint8_t *src[],
 
 #undef output_pixel
 
+static int nv12tiledToPlanarWrapper(SwsContext *c, const uint8_t *src[],
+                               int srcStride[], int srcSliceY,
+                               int srcSliceH, uint8_t *dstParam[],
+                               int dstStride[])
+
+{
+    int ret = 0;
+
+    if(NULL != c) {
+
+        struct nv12TileParams *p = (struct nv12TileParams *) c->special_format;
+
+        if(NULL != p) {
+
+            if((NULL != p->t_dst[0]) && (NULL != p->t_dst[1])) {
+
+                uint8_t *dst1 = dstParam[1] + dstStride[1] * srcSliceY / 2;
+                uint8_t *dst2 = dstParam[2] + dstStride[2] * srcSliceY / 2;
+
+                ff_nv12tile_to_nv12(p->t_dst[0],(uint8_t *)src[0], p->wTiles, p->hTiles);
+                ff_nv12tile_rectify_extrapolation(p->t_dst[0], p->width, p->height);
+
+                ff_nv12tile_to_nv12(p->t_dst[1],(uint8_t *)src[1], p->wTiles, p->hTiles_UV);
+                ff_nv12tile_rectify_extrapolation(p->t_dst[1], p->width, p->height/2);
+
+                copyPlane(p->t_dst[0], srcStride[0], srcSliceY, srcSliceH, c->srcW,
+                        dstParam[0], dstStride[0]);
+
+                if (c->srcFormat == AV_PIX_FMT_NV12_TILED)
+                    deinterleaveBytes(p->t_dst[1], dst1, dst2,c->srcW / 2, srcSliceH / 2,
+                            srcStride[1], dstStride[1], dstStride[2]);
+                else
+                    deinterleaveBytes(p->t_dst[1], dst2, dst1, c->srcW / 2, srcSliceH / 2,
+                            srcStride[1], dstStride[2], dstStride[1]);
+
+                ret = srcSliceH;
+            }
+        }
+    }
+
+    return ret;
+}
+
 static int planarToYuy2Wrapper(SwsContext *c, const uint8_t *src[],
                                int srcStride[], int srcSliceY, int srcSliceH,
                                uint8_t *dstParam[], int dstStride[])
@@ -1694,6 +1738,12 @@ void ff_get_unscaled_swscale(SwsContext *c)
         (srcFormat == AV_PIX_FMT_NV12 || srcFormat == AV_PIX_FMT_NV21)) {
         c->swscale = nv12ToPlanarWrapper;
     }
+    /* nv12tiled_to_yv12 */
+    if (dstFormat == AV_PIX_FMT_YUV420P &&
+            (srcFormat == AV_PIX_FMT_NV12_TILED)) {
+        c->swscale = nv12tiledToPlanarWrapper;
+    }
+
     /* yuv2bgr */
     if ((srcFormat == AV_PIX_FMT_YUV420P || srcFormat == AV_PIX_FMT_YUV422P ||
          srcFormat == AV_PIX_FMT_YUVA420P) && isAnyRGB(dstFormat) &&
@@ -1876,9 +1926,9 @@ void ff_get_unscaled_swscale(SwsContext *c)
         (isPlanarYUV(srcFormat) && isPlanarYUV(dstFormat) &&
          c->chrDstHSubSample == c->chrSrcHSubSample &&
          c->chrDstVSubSample == c->chrSrcVSubSample &&
-         dstFormat != AV_PIX_FMT_NV12 && dstFormat != AV_PIX_FMT_NV21 &&
+         dstFormat != AV_PIX_FMT_NV12 && dstFormat != AV_PIX_FMT_NV21 && dstFormat != AV_PIX_FMT_NV12_TILED &&
          dstFormat != AV_PIX_FMT_P010LE && dstFormat != AV_PIX_FMT_P010BE &&
-         srcFormat != AV_PIX_FMT_NV12 && srcFormat != AV_PIX_FMT_NV21 &&
+         srcFormat != AV_PIX_FMT_NV12 && srcFormat != AV_PIX_FMT_NV21 && srcFormat != AV_PIX_FMT_NV12_TILED &&
          srcFormat != AV_PIX_FMT_P010LE && srcFormat != AV_PIX_FMT_P010BE))
     {
         if (isPacked(c->srcFormat))
diff --git a/libswscale/utils.c b/libswscale/utils.c
index 60a8e55..9c97285 100644
--- a/libswscale/utils.c
+++ b/libswscale/utils.c
@@ -62,6 +62,7 @@
 #include "rgb2rgb.h"
 #include "swscale.h"
 #include "swscale_internal.h"
+#include "nv12tiled2nv12.h"
 
 #if !FF_API_SWS_VECTOR
 static SwsVector *sws_getIdentityVec(void);
@@ -122,6 +123,7 @@ static const FormatEntry format_entries[AV_PIX_FMT_NB] = {
     [AV_PIX_FMT_RGB4]        = { 0, 1 },
     [AV_PIX_FMT_RGB4_BYTE]   = { 1, 1 },
     [AV_PIX_FMT_NV12]        = { 1, 1 },
+    [AV_PIX_FMT_NV12_TILED]  = { 1, 0 },
     [AV_PIX_FMT_NV21]        = { 1, 1 },
     [AV_PIX_FMT_ARGB]        = { 1, 1 },
     [AV_PIX_FMT_RGBA]        = { 1, 1 },
@@ -1786,6 +1788,14 @@ av_cold int sws_init_context(SwsContext *c, SwsFilter *srcFilter,
         (c->srcRange == c->dstRange || isAnyRGB(dstFormat))) {
         ff_get_unscaled_swscale(c);
 
+        if(c->srcFormat == AV_PIX_FMT_NV12_TILED) {
+            if(NULL == (c->special_format = (void *) ff_nv12tile_params_init(c->srcW, c->srcH))) {
+                av_log(c, AV_LOG_ERROR, "Unable to initialize nv12tile parameters."
+                        "Make sure that given resolution is supported for NV12 Tile format\n");
+                goto fail;
+            }
+        }
+
         if (c->swscale) {
             if (flags & SWS_PRINT_INFO)
                 av_log(c, AV_LOG_INFO,
@@ -2284,6 +2294,15 @@ void sws_freeContext(SwsContext *c)
     for (i = 0; i < 4; i++)
         av_freep(&c->dither_error[i]);
 
+    if(c->special_format) {
+
+        if(c->srcFormat == AV_PIX_FMT_NV12_TILED) {
+            ff_nv12tile_params_deinit(c->special_format);
+        }
+
+        c->special_format = NULL;
+    }
+
     av_freep(&c->vLumFilter);
     av_freep(&c->vChrFilter);
     av_freep(&c->hLumFilter);
-- 
1.9.1

