1/* 2 * Android MediaCodec software buffer copy functions 3 * 4 * Copyright (c) 2015-2016 Matthieu Bouron <matthieu.bouron stupeflix.com> 5 * 6 * This file is part of FFmpeg. 7 * 8 * FFmpeg is free software; you can redistribute it and/or 9 * modify it under the terms of the GNU Lesser General Public 10 * License as published by the Free Software Foundation; either 11 * version 2.1 of the License, or (at your option) any later version. 12 * 13 * FFmpeg is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 * Lesser General Public License for more details. 17 * 18 * You should have received a copy of the GNU Lesser General Public 19 * License along with FFmpeg; if not, write to the Free Software 20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 21 */ 22 23#include <string.h> 24#include <sys/types.h> 25 26#include "libavutil/frame.h" 27#include "libavutil/mem.h" 28 29#include "avcodec.h" 30#include "mediacodec_wrapper.h" 31#include "mediacodec_sw_buffer.h" 32#include "mediacodecdec_common.h" 33 34#define QCOM_TILE_WIDTH 64 35#define QCOM_TILE_HEIGHT 32 36#define QCOM_TILE_SIZE (QCOM_TILE_WIDTH * QCOM_TILE_HEIGHT) 37#define QCOM_TILE_GROUP_SIZE (4 * QCOM_TILE_SIZE) 38 39/** 40 * The code handling the various YUV color formats is taken from the 41 * GStreamer project. 42 * 43 * Gstreamer reference: 44 * https://cgit.freedesktop.org/gstreamer/gst-plugins-bad/tree/sys/androidmedia/ 45 * 46 * Copyright (C) 2012, Collabora Ltd. 47 * Author: Sebastian Dröge <sebastian.droege@collabora.co.uk> 48 * 49 * Copyright (C) 2012, Rafaël Carré <funman@videolanorg> 50 * 51 * Copyright (C) 2015, Sebastian Dröge <sebastian@centricular.com> 52 * 53 * Copyright (C) 2014-2015, Collabora Ltd. 54 * Author: Matthieu Bouron <matthieu.bouron@gcollabora.com> 55 * 56 * Copyright (C) 2015, Edward Hervey 57 * Author: Edward Hervey <bilboed@gmail.com> 58 * 59 * Copyright (C) 2015, Matthew Waters <matthew@centricular.com> 60 * 61 * This library is free software; you can redistribute it and/or 62 * modify it under the terms of the GNU Lesser General Public 63 * License as published by the Free Software Foundation 64 * version 2.1 of the License. 65 * 66 * This library is distributed in the hope that it will be useful, 67 * but WITHOUT ANY WARRANTY; without even the implied warranty of 68 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 69 * Lesser General Public License for more details. 70 * 71 * You should have received a copy of the GNU Lesser General Public 72 * License along with this library; if not, write to the Free Software 73 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 74 * 75 */ 76void ff_mediacodec_sw_buffer_copy_yuv420_planar(AVCodecContext *avctx, 77 MediaCodecDecContext *s, 78 uint8_t *data, 79 size_t size, 80 FFAMediaCodecBufferInfo *info, 81 AVFrame *frame) 82{ 83 int i; 84 uint8_t *src = NULL; 85 86 for (i = 0; i < 3; i++) { 87 int stride = s->stride; 88 int height; 89 90 src = data + info->offset; 91 if (i == 0) { 92 height = avctx->height; 93 94 src += s->crop_top * s->stride; 95 src += s->crop_left; 96 } else { 97 height = avctx->height / 2; 98 stride = (s->stride + 1) / 2; 99 100 src += s->slice_height * s->stride; 101 102 if (i == 2) { 103 src += ((s->slice_height + 1) / 2) * stride; 104 } 105 106 src += s->crop_top * stride; 107 src += (s->crop_left / 2); 108 } 109 110 if (frame->linesize[i] == stride) { 111 memcpy(frame->data[i], src, height * stride); 112 } else { 113 int j, width; 114 uint8_t *dst = frame->data[i]; 115 116 if (i == 0) { 117 width = avctx->width; 118 } else if (i >= 1) { 119 width = FFMIN(frame->linesize[i], FFALIGN(avctx->width, 2) / 2); 120 } 121 122 for (j = 0; j < height; j++) { 123 memcpy(dst, src, width); 124 src += stride; 125 dst += frame->linesize[i]; 126 } 127 } 128 } 129} 130 131void ff_mediacodec_sw_buffer_copy_yuv420_semi_planar(AVCodecContext *avctx, 132 MediaCodecDecContext *s, 133 uint8_t *data, 134 size_t size, 135 FFAMediaCodecBufferInfo *info, 136 AVFrame *frame) 137{ 138 int i; 139 uint8_t *src = NULL; 140 141 for (i = 0; i < 2; i++) { 142 int height; 143 144 src = data + info->offset; 145 if (i == 0) { 146 height = avctx->height; 147 148 src += s->crop_top * s->stride; 149 src += s->crop_left; 150 } else if (i == 1) { 151 height = avctx->height / 2; 152 153 src += s->slice_height * s->stride; 154 src += s->crop_top * s->stride; 155 src += s->crop_left; 156 } 157 158 if (frame->linesize[i] == s->stride) { 159 memcpy(frame->data[i], src, height * s->stride); 160 } else { 161 int j, width; 162 uint8_t *dst = frame->data[i]; 163 164 if (i == 0) { 165 width = avctx->width; 166 } else if (i == 1) { 167 width = FFMIN(frame->linesize[i], FFALIGN(avctx->width, 2)); 168 } 169 170 for (j = 0; j < height; j++) { 171 memcpy(dst, src, width); 172 src += s->stride; 173 dst += frame->linesize[i]; 174 } 175 } 176 } 177} 178 179 180 181void ff_mediacodec_sw_buffer_copy_yuv420_packed_semi_planar(AVCodecContext *avctx, 182 MediaCodecDecContext *s, 183 uint8_t *data, 184 size_t size, 185 FFAMediaCodecBufferInfo *info, 186 AVFrame *frame) 187{ 188 int i; 189 uint8_t *src = NULL; 190 191 for (i = 0; i < 2; i++) { 192 int height; 193 194 src = data + info->offset; 195 if (i == 0) { 196 height = avctx->height; 197 } else if (i == 1) { 198 height = avctx->height / 2; 199 200 src += (s->slice_height - s->crop_top / 2) * s->stride; 201 202 src += s->crop_top * s->stride; 203 src += s->crop_left; 204 } 205 206 if (frame->linesize[i] == s->stride) { 207 memcpy(frame->data[i], src, height * s->stride); 208 } else { 209 int j, width; 210 uint8_t *dst = frame->data[i]; 211 212 if (i == 0) { 213 width = avctx->width; 214 } else if (i == 1) { 215 width = FFMIN(frame->linesize[i], FFALIGN(avctx->width, 2)); 216 } 217 218 for (j = 0; j < height; j++) { 219 memcpy(dst, src, width); 220 src += s->stride; 221 dst += frame->linesize[i]; 222 } 223 } 224 } 225} 226 227/** 228 * The code handling the QCOM_FormatYUV420PackedSemiPlanar64x32Tile2m8ka 229 * color format is taken from the VLC project. 230 * 231 * VLC reference: 232 * http://git.videolan.org/?p=vlc.git;a=blob;f=modules/codec/omxil/qcom.c;hb=HEAD 233 * 234 * VLC copyright notice: 235 * 236 ***************************************************************************** 237 * qcom.c : pixel format translation for Qualcomm tiled nv12 238 ***************************************************************************** 239 * Copyright © 2012 Rafaël Carré 240 * 241 * Authors: Rafaël Carré <funman@videolanorg> 242 * 243 * This program is free software; you can redistribute it and/or modify it 244 * under the terms of the GNU Lesser General Public License as published by 245 * the Free Software Foundation; either version 2.1 of the License, or 246 * (at your option) any later version. 247 * 248 * This program is distributed in the hope that it will be useful, 249 * but WITHOUT ANY WARRANTY; without even the implied warranty of 250 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 251 * GNU Lesser General Public License for more details. 252 * 253 * You should have received a copy of the GNU Lesser General Public License 254 * along with this program; if not, write to the Free Software Foundation, 255 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. 256 * 257 */ 258 259static size_t qcom_tile_pos(size_t x, size_t y, size_t w, size_t h) 260{ 261 size_t flim = x + (y & ~1) * w; 262 263 if (y & 1) { 264 flim += (x & ~3) + 2; 265 } else if ((h & 1) == 0 || y != (h - 1)) { 266 flim += (x + 2) & ~3; 267 } 268 269 return flim; 270} 271 272void ff_mediacodec_sw_buffer_copy_yuv420_packed_semi_planar_64x32Tile2m8ka(AVCodecContext *avctx, 273 MediaCodecDecContext *s, 274 uint8_t *data, 275 size_t size, 276 FFAMediaCodecBufferInfo *info, 277 AVFrame *frame) 278{ 279 size_t width = frame->width; 280 size_t linesize = frame->linesize[0]; 281 size_t height = frame->height; 282 283 const size_t tile_w = (width - 1) / QCOM_TILE_WIDTH + 1; 284 const size_t tile_w_align = (tile_w + 1) & ~1; 285 const size_t tile_h_luma = (height - 1) / QCOM_TILE_HEIGHT + 1; 286 const size_t tile_h_chroma = (height / 2 - 1) / QCOM_TILE_HEIGHT + 1; 287 288 size_t luma_size = tile_w_align * tile_h_luma * QCOM_TILE_SIZE; 289 if((luma_size % QCOM_TILE_GROUP_SIZE) != 0) 290 luma_size = (((luma_size - 1) / QCOM_TILE_GROUP_SIZE) + 1) * QCOM_TILE_GROUP_SIZE; 291 292 for(size_t y = 0; y < tile_h_luma; y++) { 293 size_t row_width = width; 294 for(size_t x = 0; x < tile_w; x++) { 295 size_t tile_width = row_width; 296 size_t tile_height = height; 297 /* dest luma memory index for this tile */ 298 size_t luma_idx = y * QCOM_TILE_HEIGHT * linesize + x * QCOM_TILE_WIDTH; 299 /* dest chroma memory index for this tile */ 300 /* XXX: remove divisions */ 301 size_t chroma_idx = (luma_idx / linesize) * linesize / 2 + (luma_idx % linesize); 302 303 /* luma source pointer for this tile */ 304 const uint8_t *src_luma = data 305 + qcom_tile_pos(x, y,tile_w_align, tile_h_luma) * QCOM_TILE_SIZE; 306 307 /* chroma source pointer for this tile */ 308 const uint8_t *src_chroma = data + luma_size 309 + qcom_tile_pos(x, y/2, tile_w_align, tile_h_chroma) * QCOM_TILE_SIZE; 310 if (y & 1) 311 src_chroma += QCOM_TILE_SIZE/2; 312 313 /* account for right columns */ 314 if (tile_width > QCOM_TILE_WIDTH) 315 tile_width = QCOM_TILE_WIDTH; 316 317 /* account for bottom rows */ 318 if (tile_height > QCOM_TILE_HEIGHT) 319 tile_height = QCOM_TILE_HEIGHT; 320 321 tile_height /= 2; 322 while (tile_height--) { 323 memcpy(frame->data[0] + luma_idx, src_luma, tile_width); 324 src_luma += QCOM_TILE_WIDTH; 325 luma_idx += linesize; 326 327 memcpy(frame->data[0] + luma_idx, src_luma, tile_width); 328 src_luma += QCOM_TILE_WIDTH; 329 luma_idx += linesize; 330 331 memcpy(frame->data[1] + chroma_idx, src_chroma, tile_width); 332 src_chroma += QCOM_TILE_WIDTH; 333 chroma_idx += linesize; 334 } 335 row_width -= QCOM_TILE_WIDTH; 336 } 337 height -= QCOM_TILE_HEIGHT; 338 } 339} 340