340 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			340 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/*
 | 
						|
 * Android MediaCodec software buffer copy functions
 | 
						|
 *
 | 
						|
 * Copyright (c) 2015-2016 Matthieu Bouron <matthieu.bouron stupeflix.com>
 | 
						|
 *
 | 
						|
 * 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 <string.h>
 | 
						|
#include <sys/types.h>
 | 
						|
 | 
						|
#include "libavutil/frame.h"
 | 
						|
#include "libavutil/mem.h"
 | 
						|
 | 
						|
#include "avcodec.h"
 | 
						|
#include "mediacodecdec.h"
 | 
						|
#include "mediacodec_wrapper.h"
 | 
						|
#include "mediacodec_sw_buffer.h"
 | 
						|
 | 
						|
#define QCOM_TILE_WIDTH 64
 | 
						|
#define QCOM_TILE_HEIGHT 32
 | 
						|
#define QCOM_TILE_SIZE (QCOM_TILE_WIDTH * QCOM_TILE_HEIGHT)
 | 
						|
#define QCOM_TILE_GROUP_SIZE (4 * QCOM_TILE_SIZE)
 | 
						|
 | 
						|
/**
 | 
						|
 * The code handling the various YUV color formats is taken from the
 | 
						|
 * GStreamer project.
 | 
						|
 *
 | 
						|
 * Gstreamer reference:
 | 
						|
 * https://cgit.freedesktop.org/gstreamer/gst-plugins-bad/tree/sys/androidmedia/
 | 
						|
 *
 | 
						|
 * Copyright (C) 2012, Collabora Ltd.
 | 
						|
 *   Author: Sebastian Dröge <sebastian.droege@collabora.co.uk>
 | 
						|
 *
 | 
						|
 * Copyright (C) 2012, Rafaël Carré <funman@videolanorg>
 | 
						|
 *
 | 
						|
 * Copyright (C) 2015, Sebastian Dröge <sebastian@centricular.com>
 | 
						|
 *
 | 
						|
 * Copyright (C) 2014-2015, Collabora Ltd.
 | 
						|
 *   Author: Matthieu Bouron <matthieu.bouron@gcollabora.com>
 | 
						|
 *
 | 
						|
 * Copyright (C) 2015, Edward Hervey
 | 
						|
 *   Author: Edward Hervey <bilboed@gmail.com>
 | 
						|
 *
 | 
						|
 * Copyright (C) 2015, Matthew Waters <matthew@centricular.com>
 | 
						|
 *
 | 
						|
 * This library 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
 | 
						|
 * version 2.1 of the License.
 | 
						|
 *
 | 
						|
 * This library 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 this library; if not, write to the Free Software
 | 
						|
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA
 | 
						|
 *
 | 
						|
 */
 | 
						|
void ff_mediacodec_sw_buffer_copy_yuv420_planar(AVCodecContext *avctx,
 | 
						|
                                                MediaCodecDecContext *s,
 | 
						|
                                                uint8_t *data,
 | 
						|
                                                size_t size,
 | 
						|
                                                FFAMediaCodecBufferInfo *info,
 | 
						|
                                                AVFrame *frame)
 | 
						|
{
 | 
						|
    int i;
 | 
						|
    uint8_t *src = NULL;
 | 
						|
 | 
						|
    for (i = 0; i < 3; i++) {
 | 
						|
        int stride = s->stride;
 | 
						|
        int height;
 | 
						|
 | 
						|
        src = data + info->offset;
 | 
						|
        if (i == 0) {
 | 
						|
            height = avctx->height;
 | 
						|
 | 
						|
            src += s->crop_top * s->stride;
 | 
						|
            src += s->crop_left;
 | 
						|
        } else {
 | 
						|
            height = avctx->height / 2;
 | 
						|
            stride = (s->stride + 1) / 2;
 | 
						|
 | 
						|
            src += s->slice_height * s->stride;
 | 
						|
 | 
						|
            if (i == 2) {
 | 
						|
                src += ((s->slice_height + 1) / 2) * stride;
 | 
						|
            }
 | 
						|
 | 
						|
            src += s->crop_top * stride;
 | 
						|
            src += (s->crop_left / 2);
 | 
						|
        }
 | 
						|
 | 
						|
        if (frame->linesize[i] == stride) {
 | 
						|
            memcpy(frame->data[i], src, height * stride);
 | 
						|
        } else {
 | 
						|
            int j, width;
 | 
						|
            uint8_t *dst = frame->data[i];
 | 
						|
 | 
						|
            if (i == 0) {
 | 
						|
                width = avctx->width;
 | 
						|
            } else if (i >= 1) {
 | 
						|
                width = FFMIN(frame->linesize[i], FFALIGN(avctx->width, 2) / 2);
 | 
						|
            }
 | 
						|
 | 
						|
            for (j = 0; j < height; j++) {
 | 
						|
                memcpy(dst, src, width);
 | 
						|
                src += stride;
 | 
						|
                dst += frame->linesize[i];
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
void ff_mediacodec_sw_buffer_copy_yuv420_semi_planar(AVCodecContext *avctx,
 | 
						|
                                                     MediaCodecDecContext *s,
 | 
						|
                                                     uint8_t *data,
 | 
						|
                                                     size_t size,
 | 
						|
                                                     FFAMediaCodecBufferInfo *info,
 | 
						|
                                                     AVFrame *frame)
 | 
						|
{
 | 
						|
    int i;
 | 
						|
    uint8_t *src = NULL;
 | 
						|
 | 
						|
    for (i = 0; i < 2; i++) {
 | 
						|
        int height;
 | 
						|
 | 
						|
        src = data + info->offset;
 | 
						|
        if (i == 0) {
 | 
						|
            height = avctx->height;
 | 
						|
 | 
						|
            src += s->crop_top * s->stride;
 | 
						|
            src += s->crop_left;
 | 
						|
        } else if (i == 1) {
 | 
						|
            height = avctx->height / 2;
 | 
						|
 | 
						|
            src += s->slice_height * s->stride;
 | 
						|
            src += s->crop_top * s->stride;
 | 
						|
            src += s->crop_left;
 | 
						|
        }
 | 
						|
 | 
						|
        if (frame->linesize[i] == s->stride) {
 | 
						|
            memcpy(frame->data[i], src, height * s->stride);
 | 
						|
        } else {
 | 
						|
            int j, width;
 | 
						|
            uint8_t *dst = frame->data[i];
 | 
						|
 | 
						|
            if (i == 0) {
 | 
						|
                width = avctx->width;
 | 
						|
            } else if (i == 1) {
 | 
						|
                width = FFMIN(frame->linesize[i], FFALIGN(avctx->width, 2));
 | 
						|
            }
 | 
						|
 | 
						|
            for (j = 0; j < height; j++) {
 | 
						|
                memcpy(dst, src, width);
 | 
						|
                src += s->stride;
 | 
						|
                dst += frame->linesize[i];
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
void ff_mediacodec_sw_buffer_copy_yuv420_packed_semi_planar(AVCodecContext *avctx,
 | 
						|
                                                            MediaCodecDecContext *s,
 | 
						|
                                                            uint8_t *data,
 | 
						|
                                                            size_t size,
 | 
						|
                                                            FFAMediaCodecBufferInfo *info,
 | 
						|
                                                            AVFrame *frame)
 | 
						|
{
 | 
						|
    int i;
 | 
						|
    uint8_t *src = NULL;
 | 
						|
 | 
						|
    for (i = 0; i < 2; i++) {
 | 
						|
        int height;
 | 
						|
 | 
						|
        src = data + info->offset;
 | 
						|
        if (i == 0) {
 | 
						|
            height = avctx->height;
 | 
						|
        } else if (i == 1) {
 | 
						|
            height = avctx->height / 2;
 | 
						|
 | 
						|
            src += (s->slice_height - s->crop_top / 2) * s->stride;
 | 
						|
 | 
						|
            src += s->crop_top * s->stride;
 | 
						|
            src += s->crop_left;
 | 
						|
        }
 | 
						|
 | 
						|
        if (frame->linesize[i] == s->stride) {
 | 
						|
            memcpy(frame->data[i], src, height * s->stride);
 | 
						|
        } else {
 | 
						|
            int j, width;
 | 
						|
            uint8_t *dst = frame->data[i];
 | 
						|
 | 
						|
            if (i == 0) {
 | 
						|
                width = avctx->width;
 | 
						|
            } else if (i == 1) {
 | 
						|
                width = FFMIN(frame->linesize[i], FFALIGN(avctx->width, 2));
 | 
						|
            }
 | 
						|
 | 
						|
            for (j = 0; j < height; j++) {
 | 
						|
                memcpy(dst, src, width);
 | 
						|
                src += s->stride;
 | 
						|
                dst += frame->linesize[i];
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * The code handling the QCOM_FormatYUV420PackedSemiPlanar64x32Tile2m8ka
 | 
						|
 * color format is taken from the VLC project.
 | 
						|
 *
 | 
						|
 * VLC reference:
 | 
						|
 * http://git.videolan.org/?p=vlc.git;a=blob;f=modules/codec/omxil/qcom.c;hb=HEAD
 | 
						|
 *
 | 
						|
 * VLC copyright notice:
 | 
						|
 *
 | 
						|
 *****************************************************************************
 | 
						|
 * qcom.c : pixel format translation for Qualcomm tiled nv12
 | 
						|
 *****************************************************************************
 | 
						|
 * Copyright © 2012 Rafaël Carré
 | 
						|
 *
 | 
						|
 * Authors: Rafaël Carré <funman@videolanorg>
 | 
						|
 *
 | 
						|
 * This program 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.
 | 
						|
 *
 | 
						|
 * This program 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 this program; if not, write to the Free Software Foundation,
 | 
						|
 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
 | 
						|
 *
 | 
						|
 */
 | 
						|
 | 
						|
static size_t qcom_tile_pos(size_t x, size_t y, size_t w, size_t h)
 | 
						|
{
 | 
						|
  size_t flim = x + (y & ~1) * w;
 | 
						|
 | 
						|
  if (y & 1) {
 | 
						|
    flim += (x & ~3) + 2;
 | 
						|
  } else if ((h & 1) == 0 || y != (h - 1)) {
 | 
						|
    flim += (x + 2) & ~3;
 | 
						|
  }
 | 
						|
 | 
						|
  return flim;
 | 
						|
}
 | 
						|
 | 
						|
void ff_mediacodec_sw_buffer_copy_yuv420_packed_semi_planar_64x32Tile2m8ka(AVCodecContext *avctx,
 | 
						|
                                                                           MediaCodecDecContext *s,
 | 
						|
                                                                           uint8_t *data,
 | 
						|
                                                                           size_t size,
 | 
						|
                                                                           FFAMediaCodecBufferInfo *info,
 | 
						|
                                                                           AVFrame *frame)
 | 
						|
{
 | 
						|
    size_t width = frame->width;
 | 
						|
    size_t linesize = frame->linesize[0];
 | 
						|
    size_t height = frame->height;
 | 
						|
 | 
						|
    const size_t tile_w = (width - 1) / QCOM_TILE_WIDTH + 1;
 | 
						|
    const size_t tile_w_align = (tile_w + 1) & ~1;
 | 
						|
    const size_t tile_h_luma = (height - 1) / QCOM_TILE_HEIGHT + 1;
 | 
						|
    const size_t tile_h_chroma = (height / 2 - 1) / QCOM_TILE_HEIGHT + 1;
 | 
						|
 | 
						|
    size_t luma_size = tile_w_align * tile_h_luma * QCOM_TILE_SIZE;
 | 
						|
    if((luma_size % QCOM_TILE_GROUP_SIZE) != 0)
 | 
						|
        luma_size = (((luma_size - 1) / QCOM_TILE_GROUP_SIZE) + 1) * QCOM_TILE_GROUP_SIZE;
 | 
						|
 | 
						|
    for(size_t y = 0; y < tile_h_luma; y++) {
 | 
						|
        size_t row_width = width;
 | 
						|
        for(size_t x = 0; x < tile_w; x++) {
 | 
						|
            size_t tile_width = row_width;
 | 
						|
            size_t tile_height = height;
 | 
						|
            /* dest luma memory index for this tile */
 | 
						|
            size_t luma_idx = y * QCOM_TILE_HEIGHT * linesize + x * QCOM_TILE_WIDTH;
 | 
						|
            /* dest chroma memory index for this tile */
 | 
						|
            /* XXX: remove divisions */
 | 
						|
            size_t chroma_idx = (luma_idx / linesize) * linesize / 2 + (luma_idx % linesize);
 | 
						|
 | 
						|
            /* luma source pointer for this tile */
 | 
						|
            const uint8_t *src_luma  = data
 | 
						|
                + qcom_tile_pos(x, y,tile_w_align, tile_h_luma) * QCOM_TILE_SIZE;
 | 
						|
 | 
						|
            /* chroma source pointer for this tile */
 | 
						|
            const uint8_t *src_chroma = data + luma_size
 | 
						|
                + qcom_tile_pos(x, y/2, tile_w_align, tile_h_chroma) * QCOM_TILE_SIZE;
 | 
						|
            if (y & 1)
 | 
						|
                src_chroma += QCOM_TILE_SIZE/2;
 | 
						|
 | 
						|
            /* account for right columns */
 | 
						|
            if (tile_width > QCOM_TILE_WIDTH)
 | 
						|
                tile_width = QCOM_TILE_WIDTH;
 | 
						|
 | 
						|
            /* account for bottom rows */
 | 
						|
            if (tile_height > QCOM_TILE_HEIGHT)
 | 
						|
                tile_height = QCOM_TILE_HEIGHT;
 | 
						|
 | 
						|
            tile_height /= 2;
 | 
						|
            while (tile_height--) {
 | 
						|
                memcpy(frame->data[0] + luma_idx, src_luma, tile_width);
 | 
						|
                src_luma += QCOM_TILE_WIDTH;
 | 
						|
                luma_idx += linesize;
 | 
						|
 | 
						|
                memcpy(frame->data[0] + luma_idx, src_luma, tile_width);
 | 
						|
                src_luma += QCOM_TILE_WIDTH;
 | 
						|
                luma_idx += linesize;
 | 
						|
 | 
						|
                memcpy(frame->data[1] + chroma_idx, src_chroma, tile_width);
 | 
						|
                src_chroma += QCOM_TILE_WIDTH;
 | 
						|
                chroma_idx += linesize;
 | 
						|
            }
 | 
						|
            row_width -= QCOM_TILE_WIDTH;
 | 
						|
        }
 | 
						|
        height -= QCOM_TILE_HEIGHT;
 | 
						|
    }
 | 
						|
}
 |