You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

340 lines
12KB

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