mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-23 08:46:40 +00:00
mfc: Remove mfc plugin, it is obsoleted by the v4l2videodec element from gst-plugins-good
This commit is contained in:
parent
24224f86bc
commit
90643c696f
11 changed files with 4 additions and 2981 deletions
|
@ -117,7 +117,8 @@ CRUFT_DIRS = \
|
|||
$(top_srcdir)/ext/swfdec \
|
||||
$(top_srcdir)/ext/tarkin \
|
||||
$(top_srcdir)/ext/theora \
|
||||
$(top_srcdir)/ext/vp8
|
||||
$(top_srcdir)/ext/vp8 \
|
||||
$(top_srcdir)/sys/mfc
|
||||
|
||||
include $(top_srcdir)/common/cruft.mak
|
||||
|
||||
|
|
50
configure.ac
50
configure.ac
|
@ -1691,55 +1691,6 @@ AG_GST_CHECK_FEATURE(SHM, [POSIX shared memory source and sink], shm, [
|
|||
fi
|
||||
])
|
||||
|
||||
dnl *** Video 4 Linux 2 ***
|
||||
dnl for information about the header/define, see sys/v4l2/gstv4l2element.h
|
||||
dnl renamed to GST_V4L2 because of some conflict with kernel headers
|
||||
translit(dnm, m, l) AM_CONDITIONAL(USE_MFC, true)
|
||||
AG_GST_CHECK_FEATURE(MFC, [Multi Format Codec], mfc, [
|
||||
AC_MSG_CHECKING([Checking for up to date v4l2 installation])
|
||||
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
|
||||
#include <sys/types.h>
|
||||
#ifdef __sun /* Solaris */
|
||||
#include <sys/types.h>
|
||||
#include <sys/videodev2.h>
|
||||
#elif __FreeBSD__
|
||||
#include <linux/videodev2.h>
|
||||
#else /* Linux */
|
||||
#include <linux/types.h>
|
||||
#define _LINUX_TIME_H
|
||||
#define __user
|
||||
#include <linux/videodev2.h>
|
||||
#endif
|
||||
#if defined(V4L2_MAJOR_VERSION) || defined(V4L2_MINOR_VERSION)
|
||||
#error too early v4l2 version or no v4l2 at all
|
||||
#endif
|
||||
#if !defined(V4L2_PIX_FMT_H264)
|
||||
#error v4l2 version too old
|
||||
#endif
|
||||
]], [[
|
||||
return 0;
|
||||
]])],[
|
||||
HAVE_MFC="yes"
|
||||
AC_MSG_RESULT(yes)
|
||||
],[
|
||||
HAVE_MFC="no"
|
||||
AC_MSG_RESULT(no)
|
||||
|
||||
HAVE_VIDEODEV=no
|
||||
AC_CHECK_HEADER(linux/videodev2.h, [ HAVE_VIDEODEV=yes ],
|
||||
[
|
||||
AC_CHECK_HEADER(sys/videodev2.h, [ HAVE_VIDEODEV=yes ])
|
||||
])
|
||||
|
||||
if test "x$HAVE_VIDEODEV" = "xyes"; then
|
||||
AC_MSG_WARN([video4linux2 headers were found, but they're old.])
|
||||
AC_MSG_WARN([Please update v4l2 to compile the MFC plugins])
|
||||
else
|
||||
AC_MSG_WARN([v4l2 was not found])
|
||||
fi
|
||||
])
|
||||
])
|
||||
|
||||
dnl check for Video CD
|
||||
translit(dnm, m, l) AM_CONDITIONAL(USE_VCD, true)
|
||||
AG_GST_CHECK_FEATURE(VCD, [Video CD], vcdsrc, [
|
||||
|
@ -3222,7 +3173,6 @@ sys/linsys/Makefile
|
|||
sys/opensles/Makefile
|
||||
sys/osxvideo/Makefile
|
||||
sys/qtwrapper/Makefile
|
||||
sys/mfc/Makefile
|
||||
sys/shm/Makefile
|
||||
sys/uvch264/Makefile
|
||||
sys/vcd/Makefile
|
||||
|
|
|
@ -160,15 +160,9 @@ else
|
|||
UVCH264_DIR=
|
||||
endif
|
||||
|
||||
if USE_MFC
|
||||
MFC_DIR=mfc
|
||||
else
|
||||
MFC_DIR=
|
||||
endif
|
||||
|
||||
SUBDIRS = $(ACM_DIR) $(ANDROID_MEDIA_DIR) $(APPLE_MEDIA_DIR) $(AVC_DIR) $(BLUEZ_DIR) $(D3DVIDEOSINK_DIR) $(DECKLINK_DIR) $(DIRECTDRAW_DIR) $(DIRECTSOUND_DIR) $(WINKS_DIR) $(DVB_DIR) $(FBDEV_DIR) $(LINSYS_DIR) $(OPENSLES_DIR) $(OSX_VIDEO_DIR) $(PVR_DIR) $(QT_DIR) $(SHM_DIR) $(UVCH264_DIR) $(VCD_DIR) $(VDPAU_DIR) $(WININET_DIR) $(WINSCREENCAP_DIR) $(WASAPI_DIR) $(MFC_DIR)
|
||||
SUBDIRS = $(ACM_DIR) $(ANDROID_MEDIA_DIR) $(APPLE_MEDIA_DIR) $(AVC_DIR) $(BLUEZ_DIR) $(D3DVIDEOSINK_DIR) $(DECKLINK_DIR) $(DIRECTDRAW_DIR) $(DIRECTSOUND_DIR) $(WINKS_DIR) $(DVB_DIR) $(FBDEV_DIR) $(LINSYS_DIR) $(OPENSLES_DIR) $(OSX_VIDEO_DIR) $(PVR_DIR) $(QT_DIR) $(SHM_DIR) $(UVCH264_DIR) $(VCD_DIR) $(VDPAU_DIR) $(WININET_DIR) $(WINSCREENCAP_DIR) $(WASAPI_DIR)
|
||||
|
||||
DIST_SUBDIRS = acmenc acmmp3dec androidmedia applemedia applemedia-nonpublic avc bluez d3dvideosink decklink directdraw directsound dvb linsys fbdev dshowdecwrapper dshowsrcwrapper dshowvideosink \
|
||||
opensles osxvideo pvr2d qtwrapper shm uvch264 vcd vdpau wasapi wininet winks winscreencap mfc
|
||||
opensles osxvideo pvr2d qtwrapper shm uvch264 vcd vdpau wasapi wininet winks winscreencap
|
||||
|
||||
include $(top_srcdir)/common/parallel-subdirs.mak
|
||||
|
|
|
@ -1,26 +0,0 @@
|
|||
plugin_LTLIBRARIES = libgstmfc.la
|
||||
|
||||
libgstmfc_la_SOURCES = \
|
||||
mfc_decoder/mfc_decoder.c \
|
||||
fimc/fimc.c \
|
||||
gstmfc.c \
|
||||
gstmfcdec.c
|
||||
|
||||
noinst_HEADERS = \
|
||||
mfc_decoder/mfc_decoder.h \
|
||||
fimc/fimc.h \
|
||||
gstmfcdec.h
|
||||
|
||||
libgstmfc_la_CFLAGS = \
|
||||
$(GST_PLUGINS_BASE_CFLAGS) \
|
||||
$(GST_BASE_CFLAGS) \
|
||||
$(GST_CFLAGS) \
|
||||
-I$(srcdir)
|
||||
libgstmfc_la_LIBADD = \
|
||||
$(GST_PLUGINS_BASE_LIBS) \
|
||||
-lgstvideo-@GST_API_VERSION@ \
|
||||
$(GST_BASE_LIBS) \
|
||||
$(GST_LIBS)
|
||||
libgstmfc_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
|
||||
libgstmfc_la_LIBTOOLFLAGS = $(GST_PLUGIN_LIBTOOLFLAGS)
|
||||
|
|
@ -1,664 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2012 Collabora Ltd.
|
||||
* Author: Sebastian Dröge <sebastian.droege@collabora.co.uk>
|
||||
*
|
||||
* This library is licensed under 2 different licenses and you
|
||||
* can choose to use it under the terms of any one of them. The
|
||||
* two licenses are the Apache License 2.0 and the LGPL.
|
||||
*
|
||||
* Apache License 2.0:
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* LGPL:
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* 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
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/mman.h>
|
||||
#include <string.h>
|
||||
#include <linux/videodev2.h>
|
||||
|
||||
/* for g_atomic_* */
|
||||
#include <glib.h>
|
||||
|
||||
/* For logging */
|
||||
#include <gst/gst.h>
|
||||
GST_DEBUG_CATEGORY (fimc_debug);
|
||||
#define GST_CAT_DEFAULT fimc_debug
|
||||
|
||||
#include "fimc.h"
|
||||
|
||||
struct _Fimc
|
||||
{
|
||||
int fd;
|
||||
|
||||
struct v4l2_capability caps;
|
||||
|
||||
int set_src;
|
||||
int has_src_buffers;
|
||||
int streamon_src;
|
||||
FimcColorFormat src_format;
|
||||
struct v4l2_format src_fmt;
|
||||
struct v4l2_crop src_crop;
|
||||
struct v4l2_requestbuffers src_requestbuffers;
|
||||
|
||||
int set_dst;
|
||||
int has_dst_buffers;
|
||||
int streamon_dst;
|
||||
FimcColorFormat dst_format;
|
||||
struct v4l2_format dst_fmt;
|
||||
struct v4l2_crop dst_crop;
|
||||
struct v4l2_requestbuffers dst_requestbuffers;
|
||||
|
||||
struct v4l2_plane dst_planes[3];
|
||||
struct v4l2_buffer dst_buffer;
|
||||
void *dst_buffer_data[3];
|
||||
int dst_buffer_size[3];
|
||||
};
|
||||
|
||||
#define FIMC_PATH "/dev/video4"
|
||||
|
||||
static volatile int fimc_in_use;
|
||||
|
||||
void
|
||||
fimc_init_debug (void)
|
||||
{
|
||||
GST_DEBUG_CATEGORY_INIT (fimc_debug, "fimc", 0, "FIMC library");
|
||||
}
|
||||
|
||||
Fimc *
|
||||
fimc_new (void)
|
||||
{
|
||||
Fimc *fimc;
|
||||
|
||||
if (!g_atomic_int_compare_and_exchange (&fimc_in_use, FALSE, TRUE)) {
|
||||
GST_ERROR ("Rejected because FIMC is already in use");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fimc = calloc (1, sizeof (Fimc));
|
||||
|
||||
fimc->fd = open (FIMC_PATH, O_RDWR, 0);
|
||||
if (fimc->fd == -1) {
|
||||
GST_ERROR ("Unable to open FIMC device node: %d", errno);
|
||||
fimc_free (fimc);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* check capabilities */
|
||||
|
||||
if (ioctl (fimc->fd, VIDIOC_QUERYCAP, &fimc->caps) < 0) {
|
||||
GST_ERROR ("Unable to query capabilities: %d", errno);
|
||||
fimc_free (fimc);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ((fimc->caps.capabilities & V4L2_CAP_STREAMING) == 0 ||
|
||||
(fimc->caps.capabilities & V4L2_CAP_VIDEO_OUTPUT_MPLANE) == 0 ||
|
||||
(fimc->caps.capabilities & V4L2_CAP_VIDEO_CAPTURE_MPLANE) == 0) {
|
||||
GST_ERROR ("Required capabilities not available");
|
||||
fimc_free (fimc);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
GST_DEBUG ("Created new FIMC context");
|
||||
|
||||
return fimc;
|
||||
}
|
||||
|
||||
void
|
||||
fimc_free (Fimc * fimc)
|
||||
{
|
||||
fimc_release_src_buffers (fimc);
|
||||
fimc_release_dst_buffers (fimc);
|
||||
|
||||
if (fimc->fd != -1)
|
||||
close (fimc->fd);
|
||||
|
||||
g_atomic_int_set (&fimc_in_use, FALSE);
|
||||
free (fimc);
|
||||
}
|
||||
|
||||
static int
|
||||
fimc_color_format_to_v4l2 (FimcColorFormat format)
|
||||
{
|
||||
switch (format) {
|
||||
case FIMC_COLOR_FORMAT_YUV420SPT:
|
||||
return V4L2_PIX_FMT_NV12MT;
|
||||
case FIMC_COLOR_FORMAT_YUV420SP:
|
||||
return V4L2_PIX_FMT_NV12M;
|
||||
case FIMC_COLOR_FORMAT_YUV420P:
|
||||
return V4L2_PIX_FMT_YUV420M;
|
||||
case FIMC_COLOR_FORMAT_RGB32:
|
||||
return V4L2_PIX_FMT_RGB32;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int
|
||||
fimc_color_format_get_nplanes (FimcColorFormat format)
|
||||
{
|
||||
switch (format) {
|
||||
case FIMC_COLOR_FORMAT_RGB32:
|
||||
return 1;
|
||||
case FIMC_COLOR_FORMAT_YUV420SPT:
|
||||
case FIMC_COLOR_FORMAT_YUV420SP:
|
||||
return 2;
|
||||
case FIMC_COLOR_FORMAT_YUV420P:
|
||||
return 3;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int
|
||||
fimc_color_format_get_component_height (FimcColorFormat format, int c,
|
||||
int height)
|
||||
{
|
||||
switch (format) {
|
||||
case FIMC_COLOR_FORMAT_RGB32:
|
||||
return height;
|
||||
case FIMC_COLOR_FORMAT_YUV420SPT:
|
||||
case FIMC_COLOR_FORMAT_YUV420SP:
|
||||
case FIMC_COLOR_FORMAT_YUV420P:
|
||||
if (c == 0)
|
||||
return height;
|
||||
else
|
||||
return (height + 1) / 2;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int
|
||||
fimc_set_src_format (Fimc * fimc, FimcColorFormat format, int width, int height,
|
||||
int stride[3], int crop_left, int crop_top, int crop_width, int crop_height)
|
||||
{
|
||||
struct v4l2_format fmt;
|
||||
struct v4l2_crop crop;
|
||||
struct v4l2_control control;
|
||||
int i;
|
||||
|
||||
/* Check if something changed */
|
||||
if (fimc->set_src &&
|
||||
fimc->src_fmt.fmt.pix_mp.width == width &&
|
||||
fimc->src_fmt.fmt.pix_mp.height == height &&
|
||||
fimc->src_fmt.fmt.pix_mp.pixelformat == fimc_color_format_to_v4l2 (format)
|
||||
&& fimc->src_crop.c.left == crop_left && fimc->src_crop.c.top == crop_top
|
||||
&& fimc->src_crop.c.width == crop_width
|
||||
&& fimc->src_crop.c.height == crop_height) {
|
||||
if (fimc->src_fmt.fmt.pix_mp.plane_fmt[0].bytesperline == stride[0] &&
|
||||
fimc->src_fmt.fmt.pix_mp.plane_fmt[1].bytesperline == stride[1] &&
|
||||
fimc->src_fmt.fmt.pix_mp.plane_fmt[2].bytesperline == stride[2]) {
|
||||
GST_DEBUG ("Nothing has changed");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Something has changed */
|
||||
fimc->set_src = 0;
|
||||
|
||||
memset (&fmt, 0, sizeof (fmt));
|
||||
memset (&crop, 0, sizeof (crop));
|
||||
memset (&control, 0, sizeof (control));
|
||||
|
||||
fimc->src_format = format;
|
||||
|
||||
fmt.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
|
||||
fmt.fmt.pix_mp.width = width;
|
||||
fmt.fmt.pix_mp.height = height;
|
||||
fmt.fmt.pix_mp.pixelformat = fimc_color_format_to_v4l2 (format);
|
||||
fmt.fmt.pix_mp.field = V4L2_FIELD_ANY;
|
||||
fmt.fmt.pix_mp.num_planes = fimc_color_format_get_nplanes (format);
|
||||
|
||||
for (i = 0; i < fmt.fmt.pix_mp.num_planes; i++) {
|
||||
fmt.fmt.pix_mp.plane_fmt[i].bytesperline = stride[i];
|
||||
fmt.fmt.pix_mp.plane_fmt[i].sizeimage =
|
||||
fimc_color_format_get_component_height (format, i, height) * stride[i];
|
||||
}
|
||||
|
||||
if (ioctl (fimc->fd, VIDIOC_S_FMT, &fmt) < 0) {
|
||||
GST_ERROR ("Failed to set src format: %d", errno);
|
||||
return -1;
|
||||
}
|
||||
|
||||
fimc->src_fmt = fmt;
|
||||
|
||||
crop.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
|
||||
crop.c.left = crop_left;
|
||||
crop.c.top = crop_top;
|
||||
crop.c.width = crop_width;
|
||||
crop.c.height = crop_height;
|
||||
|
||||
if (ioctl (fimc->fd, VIDIOC_S_CROP, &crop) < 0) {
|
||||
GST_ERROR ("Failed to set src crop: %d", errno);
|
||||
return -1;
|
||||
}
|
||||
|
||||
fimc->src_crop = crop;
|
||||
|
||||
control.id = V4L2_CID_ROTATE;
|
||||
control.value = 0;
|
||||
|
||||
if (ioctl (fimc->fd, VIDIOC_S_CTRL, &control) < 0) {
|
||||
GST_ERROR ("Failed to set rotation to 0: %d", errno);
|
||||
return -1;
|
||||
}
|
||||
|
||||
fimc->set_src = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
fimc_request_src_buffers (Fimc * fimc)
|
||||
{
|
||||
struct v4l2_requestbuffers requestbuffers;
|
||||
|
||||
if (fimc->has_dst_buffers) {
|
||||
GST_ERROR ("Already have dst buffers");
|
||||
return -1;
|
||||
}
|
||||
|
||||
fimc->has_src_buffers = 0;
|
||||
|
||||
memset (&requestbuffers, 0, sizeof (requestbuffers));
|
||||
|
||||
requestbuffers.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
|
||||
requestbuffers.memory = V4L2_MEMORY_USERPTR;
|
||||
requestbuffers.count = 1;
|
||||
|
||||
if (ioctl (fimc->fd, VIDIOC_REQBUFS, &requestbuffers) < 0) {
|
||||
GST_ERROR ("Failed to request src buffers: %d", errno);
|
||||
return -1;
|
||||
}
|
||||
|
||||
fimc->src_requestbuffers = requestbuffers;
|
||||
|
||||
if (requestbuffers.count < 1) {
|
||||
GST_ERROR ("Got %d buffers instead of %d", requestbuffers.count, 1);
|
||||
return -1;
|
||||
}
|
||||
|
||||
fimc->has_src_buffers = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
fimc_release_src_buffers (Fimc * fimc)
|
||||
{
|
||||
enum v4l2_buf_type type;
|
||||
|
||||
if (fimc->streamon_src) {
|
||||
type = fimc->src_requestbuffers.type;
|
||||
if (ioctl (fimc->fd, VIDIOC_STREAMOFF, &type) < 0) {
|
||||
GST_ERROR ("Deactivating input stream failed: %d", errno);
|
||||
return -1;
|
||||
}
|
||||
fimc->streamon_src = 0;
|
||||
}
|
||||
|
||||
/* Nothing to do here now */
|
||||
fimc->has_src_buffers = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
fimc_set_dst_format (Fimc * fimc, FimcColorFormat format, int width, int height,
|
||||
int stride[3], int crop_left, int crop_top, int crop_width, int crop_height)
|
||||
{
|
||||
struct v4l2_format fmt;
|
||||
struct v4l2_crop crop;
|
||||
struct v4l2_control control;
|
||||
int i;
|
||||
|
||||
/* Check if something changed */
|
||||
if (fimc->set_dst &&
|
||||
fimc->dst_fmt.fmt.pix_mp.width == width &&
|
||||
fimc->dst_fmt.fmt.pix_mp.height == height &&
|
||||
fimc->dst_fmt.fmt.pix_mp.pixelformat == fimc_color_format_to_v4l2 (format)
|
||||
&& fimc->dst_crop.c.left == crop_left && fimc->dst_crop.c.top == crop_top
|
||||
&& fimc->dst_crop.c.width == crop_width
|
||||
&& fimc->dst_crop.c.height == crop_height) {
|
||||
if (fimc->dst_fmt.fmt.pix_mp.plane_fmt[0].bytesperline == stride[0] &&
|
||||
fimc->dst_fmt.fmt.pix_mp.plane_fmt[1].bytesperline == stride[1] &&
|
||||
fimc->dst_fmt.fmt.pix_mp.plane_fmt[2].bytesperline == stride[2]) {
|
||||
GST_DEBUG ("Nothing has changed");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Something has changed */
|
||||
fimc->set_dst = 0;
|
||||
|
||||
memset (&fmt, 0, sizeof (fmt));
|
||||
memset (&crop, 0, sizeof (crop));
|
||||
memset (&control, 0, sizeof (control));
|
||||
|
||||
fimc->dst_format = format;
|
||||
|
||||
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
|
||||
fmt.fmt.pix_mp.width = width;
|
||||
fmt.fmt.pix_mp.height = height;
|
||||
fmt.fmt.pix_mp.pixelformat = fimc_color_format_to_v4l2 (format);
|
||||
fmt.fmt.pix_mp.field = V4L2_FIELD_ANY;
|
||||
fmt.fmt.pix_mp.num_planes = fimc_color_format_get_nplanes (format);
|
||||
|
||||
for (i = 0; i < fmt.fmt.pix_mp.num_planes; i++) {
|
||||
fmt.fmt.pix_mp.plane_fmt[i].bytesperline = stride[i];
|
||||
fmt.fmt.pix_mp.plane_fmt[i].sizeimage =
|
||||
fimc_color_format_get_component_height (format, i, height) * stride[i];
|
||||
}
|
||||
|
||||
if (ioctl (fimc->fd, VIDIOC_S_FMT, &fmt) < 0) {
|
||||
GST_ERROR ("Failed to set dst format: %d", errno);
|
||||
return -1;
|
||||
}
|
||||
|
||||
fimc->dst_fmt = fmt;
|
||||
|
||||
crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
|
||||
crop.c.left = crop_left;
|
||||
crop.c.top = crop_top;
|
||||
crop.c.width = crop_width;
|
||||
crop.c.height = crop_height;
|
||||
|
||||
if (ioctl (fimc->fd, VIDIOC_S_CROP, &crop) < 0) {
|
||||
GST_ERROR ("Failed to set dst crop: %d", errno);
|
||||
return -1;
|
||||
}
|
||||
|
||||
fimc->dst_crop = crop;
|
||||
|
||||
control.id = V4L2_CID_ROTATE;
|
||||
control.value = 0;
|
||||
|
||||
if (ioctl (fimc->fd, VIDIOC_S_CTRL, &control) < 0) {
|
||||
GST_ERROR ("Failed to set rotation to 0: %d", errno);
|
||||
return -1;
|
||||
}
|
||||
|
||||
fimc->set_dst = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
fimc_request_dst_buffers (Fimc * fimc)
|
||||
{
|
||||
struct v4l2_requestbuffers requestbuffers;
|
||||
|
||||
if (fimc->has_dst_buffers) {
|
||||
GST_ERROR ("Already have dst buffers");
|
||||
return -1;
|
||||
}
|
||||
|
||||
fimc->has_dst_buffers = 0;
|
||||
|
||||
memset (&requestbuffers, 0, sizeof (requestbuffers));
|
||||
|
||||
requestbuffers.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
|
||||
requestbuffers.memory = V4L2_MEMORY_USERPTR;
|
||||
requestbuffers.count = 1;
|
||||
|
||||
if (ioctl (fimc->fd, VIDIOC_REQBUFS, &requestbuffers) < 0) {
|
||||
GST_ERROR ("Failed to request dst buffers: %d", errno);
|
||||
return -1;
|
||||
}
|
||||
|
||||
fimc->dst_requestbuffers = requestbuffers;
|
||||
|
||||
if (requestbuffers.count < 1) {
|
||||
GST_ERROR ("Got %d buffers instead of %d", requestbuffers.count, 1);
|
||||
return -1;
|
||||
}
|
||||
|
||||
fimc->has_dst_buffers = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
fimc_request_dst_buffers_mmap (Fimc * fimc, void *dst[3], int stride[3])
|
||||
{
|
||||
struct v4l2_requestbuffers requestbuffers;
|
||||
struct v4l2_plane planes[3];
|
||||
struct v4l2_buffer buffer;
|
||||
int i;
|
||||
|
||||
if (fimc->has_dst_buffers) {
|
||||
GST_ERROR ("Already have dst buffers");
|
||||
return -1;
|
||||
}
|
||||
|
||||
fimc->has_dst_buffers = 0;
|
||||
|
||||
memset (&requestbuffers, 0, sizeof (requestbuffers));
|
||||
memset (planes, 0, sizeof (planes));
|
||||
memset (&buffer, 0, sizeof (buffer));
|
||||
|
||||
requestbuffers.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
|
||||
requestbuffers.memory = V4L2_MEMORY_MMAP;
|
||||
requestbuffers.count = 1;
|
||||
|
||||
if (ioctl (fimc->fd, VIDIOC_REQBUFS, &requestbuffers) < 0) {
|
||||
GST_ERROR ("Failed to request dst buffers: %d", errno);
|
||||
return -1;
|
||||
}
|
||||
|
||||
fimc->dst_requestbuffers = requestbuffers;
|
||||
|
||||
if (requestbuffers.count < 1) {
|
||||
GST_ERROR ("Got %d buffers instead of %d", requestbuffers.count, 1);
|
||||
return -1;
|
||||
}
|
||||
|
||||
buffer.type = fimc->dst_requestbuffers.type;
|
||||
buffer.memory = fimc->dst_requestbuffers.memory;
|
||||
buffer.index = 0;
|
||||
buffer.length = fimc_color_format_get_nplanes (fimc->dst_format);
|
||||
buffer.m.planes = planes;
|
||||
|
||||
if (ioctl (fimc->fd, VIDIOC_QUERYBUF, &buffer) < 0) {
|
||||
GST_ERROR ("Query of output buffers failed: %d", errno);
|
||||
return -1;
|
||||
}
|
||||
|
||||
fimc->dst_planes[0] = planes[0];
|
||||
fimc->dst_planes[1] = planes[1];
|
||||
fimc->dst_planes[2] = planes[2];
|
||||
fimc->dst_buffer = buffer;
|
||||
fimc->dst_buffer.m.planes = fimc->dst_planes;
|
||||
|
||||
for (i = 0; i < buffer.length; i++) {
|
||||
fimc->dst_buffer_data[i] =
|
||||
mmap (NULL, buffer.m.planes[i].length, PROT_READ | PROT_WRITE,
|
||||
MAP_SHARED, fimc->fd, buffer.m.planes[i].m.mem_offset);
|
||||
|
||||
if (fimc->dst_buffer_data[i] == MAP_FAILED) {
|
||||
GST_ERROR ("Failed to map output buffer %d", i);
|
||||
return -1;
|
||||
}
|
||||
fimc->dst_buffer_size[i] = buffer.m.planes[i].length;
|
||||
|
||||
dst[i] = fimc->dst_buffer_data[i];
|
||||
stride[i] = fimc->dst_fmt.fmt.pix_mp.plane_fmt[i].bytesperline;
|
||||
}
|
||||
|
||||
/* FIXME: The device reports wrong strides */
|
||||
if (fimc->dst_format == FIMC_COLOR_FORMAT_YUV420P) {
|
||||
stride[1] /= 2;
|
||||
stride[2] /= 2;
|
||||
}
|
||||
|
||||
fimc->has_dst_buffers = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
fimc_release_dst_buffers (Fimc * fimc)
|
||||
{
|
||||
enum v4l2_buf_type type;
|
||||
int i;
|
||||
|
||||
if (fimc->streamon_dst) {
|
||||
type = fimc->dst_requestbuffers.type;
|
||||
if (ioctl (fimc->fd, VIDIOC_STREAMOFF, &type) < 0) {
|
||||
GST_ERROR ("Deactivating output stream failed: %d", errno);
|
||||
return -1;
|
||||
}
|
||||
fimc->streamon_dst = 0;
|
||||
}
|
||||
|
||||
fimc->has_dst_buffers = 0;
|
||||
|
||||
for (i = 0; i < 3; i++) {
|
||||
if (fimc->dst_buffer_data[i])
|
||||
munmap (fimc->dst_buffer_data[i], fimc->dst_buffer_size[i]);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
fimc_convert (Fimc * fimc, void *src[3], void *dst[3])
|
||||
{
|
||||
struct v4l2_plane planes[3];
|
||||
struct v4l2_buffer buffer;
|
||||
enum v4l2_buf_type type;
|
||||
int i;
|
||||
|
||||
if (!fimc->set_src || !fimc->set_dst ||
|
||||
!fimc->has_src_buffers || !fimc->has_dst_buffers) {
|
||||
GST_ERROR ("Not configured yet");
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset (planes, 0, sizeof (planes));
|
||||
memset (&buffer, 0, sizeof (buffer));
|
||||
|
||||
buffer.type = fimc->src_requestbuffers.type;
|
||||
buffer.memory = fimc->src_requestbuffers.memory;
|
||||
buffer.length = fimc->src_fmt.fmt.pix_mp.num_planes;
|
||||
buffer.index = 0;
|
||||
buffer.m.planes = planes;
|
||||
|
||||
for (i = 0; i < buffer.length; i++) {
|
||||
buffer.m.planes[i].length = fimc->src_fmt.fmt.pix_mp.plane_fmt[i].sizeimage;
|
||||
buffer.m.planes[i].m.userptr = (unsigned long) src[i];
|
||||
}
|
||||
|
||||
if (ioctl (fimc->fd, VIDIOC_QBUF, &buffer) < 0) {
|
||||
GST_ERROR ("Failed to queue input buffer: %d", errno);
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset (planes, 0, sizeof (planes));
|
||||
memset (&buffer, 0, sizeof (buffer));
|
||||
|
||||
buffer.type = fimc->dst_requestbuffers.type;
|
||||
buffer.memory = fimc->dst_requestbuffers.memory;
|
||||
buffer.length = fimc->dst_fmt.fmt.pix_mp.num_planes;
|
||||
buffer.index = 0;
|
||||
buffer.m.planes = planes;
|
||||
|
||||
for (i = 0; i < buffer.length; i++) {
|
||||
buffer.m.planes[i].length = fimc->dst_fmt.fmt.pix_mp.plane_fmt[i].sizeimage;
|
||||
if (fimc->dst_requestbuffers.memory == V4L2_MEMORY_MMAP)
|
||||
buffer.m.planes[i].m.mem_offset = fimc->dst_planes[i].m.mem_offset;
|
||||
else
|
||||
buffer.m.planes[i].m.userptr = (unsigned long) dst[i];
|
||||
}
|
||||
|
||||
if (ioctl (fimc->fd, VIDIOC_QBUF, &buffer) < 0) {
|
||||
GST_ERROR ("Failed to queue output buffer: %d", errno);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!fimc->streamon_src) {
|
||||
type = fimc->src_requestbuffers.type;
|
||||
if (ioctl (fimc->fd, VIDIOC_STREAMON, &type) < 0) {
|
||||
GST_ERROR ("Activating input stream failed: %d", errno);
|
||||
return -1;
|
||||
}
|
||||
fimc->streamon_src = 1;
|
||||
}
|
||||
|
||||
if (!fimc->streamon_dst) {
|
||||
type = fimc->dst_requestbuffers.type;
|
||||
if (ioctl (fimc->fd, VIDIOC_STREAMON, &type) < 0) {
|
||||
GST_ERROR ("Activating output stream failed: %d", errno);
|
||||
return -1;
|
||||
}
|
||||
fimc->streamon_dst = 1;
|
||||
}
|
||||
|
||||
memset (planes, 0, sizeof (planes));
|
||||
memset (&buffer, 0, sizeof (buffer));
|
||||
|
||||
buffer.type = fimc->src_requestbuffers.type;
|
||||
buffer.memory = fimc->src_requestbuffers.memory;
|
||||
buffer.length = fimc->src_fmt.fmt.pix_mp.num_planes;
|
||||
buffer.m.planes = planes;
|
||||
|
||||
if (ioctl (fimc->fd, VIDIOC_DQBUF, &buffer) < 0) {
|
||||
GST_ERROR ("Failed to dequeue input buffer: %d", errno);
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset (planes, 0, sizeof (planes));
|
||||
memset (&buffer, 0, sizeof (buffer));
|
||||
|
||||
buffer.type = fimc->dst_requestbuffers.type;
|
||||
buffer.memory = fimc->dst_requestbuffers.memory;
|
||||
buffer.length = fimc->dst_fmt.fmt.pix_mp.num_planes;
|
||||
buffer.m.planes = planes;
|
||||
|
||||
if (ioctl (fimc->fd, VIDIOC_DQBUF, &buffer) < 0) {
|
||||
GST_ERROR ("Failed to dequeue output buffer: %d", errno);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -1,78 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2012 Collabora Ltd.
|
||||
* Author: Sebastian Dröge <sebastian.droege@collabora.co.uk>
|
||||
*
|
||||
* This library is licensed under 2 different licenses and you
|
||||
* can choose to use it under the terms of any one of them. The
|
||||
* two licenses are the Apache License 2.0 and the LGPL.
|
||||
*
|
||||
* Apache License 2.0:
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* LGPL:
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* 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
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __FIMC_H__
|
||||
#define __FIMC_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct _Fimc Fimc;
|
||||
|
||||
typedef enum {
|
||||
FIMC_COLOR_FORMAT_YUV420SPT,
|
||||
FIMC_COLOR_FORMAT_YUV420SP,
|
||||
FIMC_COLOR_FORMAT_YUV420P,
|
||||
FIMC_COLOR_FORMAT_RGB32
|
||||
} FimcColorFormat;
|
||||
|
||||
void fimc_init_debug (void);
|
||||
|
||||
Fimc * fimc_new (void);
|
||||
void fimc_free (Fimc * fimc);
|
||||
|
||||
int fimc_set_src_format (Fimc *fimc, FimcColorFormat format, int width, int height, int stride[3], int crop_left, int crop_top, int crop_width, int crop_height);
|
||||
int fimc_request_src_buffers (Fimc *fimc);
|
||||
int fimc_release_src_buffers (Fimc *fimc);
|
||||
|
||||
int fimc_set_dst_format (Fimc *fimc, FimcColorFormat format, int width, int height, int stride[3], int crop_left, int crop_top, int crop_width, int crop_height);
|
||||
int fimc_request_dst_buffers (Fimc *fimc);
|
||||
int fimc_request_dst_buffers_mmap (Fimc *fimc, void *dst[3], int stride[3]);
|
||||
int fimc_release_dst_buffers (Fimc *fimc);
|
||||
|
||||
int fimc_convert (Fimc *fimc, void *src[3], void *dst[3]);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __FIMC_H__ */
|
|
@ -1,57 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2012 Collabora Ltd.
|
||||
* Author: Sebastian Dröge <sebastian.droege@collabora.co.uk>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* 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
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <gst/gst.h>
|
||||
#include "gstmfcdec.h"
|
||||
|
||||
GST_DEBUG_CATEGORY_EXTERN (GST_CAT_PLUGIN_LOADING);
|
||||
|
||||
static gboolean
|
||||
plugin_init (GstPlugin * plugin)
|
||||
{
|
||||
struct mfc_dec_context *context;
|
||||
|
||||
/* Just check here once if we can create a MFC context, i.e.
|
||||
* if the hardware is available */
|
||||
mfc_dec_init_debug ();
|
||||
context = mfc_dec_create (CODEC_TYPE_H264);
|
||||
if (!context) {
|
||||
GST_CAT_DEBUG (GST_CAT_PLUGIN_LOADING,
|
||||
"Failed to initialize MFC decoder context");
|
||||
return TRUE;
|
||||
}
|
||||
mfc_dec_destroy (context);
|
||||
|
||||
if (!gst_element_register (plugin, "mfcdec", GST_RANK_PRIMARY,
|
||||
GST_TYPE_MFC_DEC))
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
|
||||
GST_VERSION_MINOR,
|
||||
mfc,
|
||||
"Samsung Exynos MFC plugin",
|
||||
plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)
|
1032
sys/mfc/gstmfcdec.c
1032
sys/mfc/gstmfcdec.c
File diff suppressed because it is too large
Load diff
|
@ -1,84 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2012 Collabora Ltd.
|
||||
* Author: Sebastian Dröge <sebastian.droege@collabora.co.uk>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* 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
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __GST_MFC_DEC_H__
|
||||
#define __GST_MFC_DEC_H__
|
||||
|
||||
#include <gst/gst.h>
|
||||
#include <gst/video/video.h>
|
||||
#include <gst/video/gstvideodecoder.h>
|
||||
#include <gst/video/gstvideometa.h>
|
||||
#include <gst/video/gstvideopool.h>
|
||||
|
||||
#include "mfc_decoder/mfc_decoder.h"
|
||||
#include "fimc/fimc.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define GST_TYPE_MFC_DEC \
|
||||
(gst_mfc_dec_get_type())
|
||||
#define GST_MFC_DEC(obj) \
|
||||
(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_MFC_DEC,GstMFCDec))
|
||||
#define GST_MFC_DEC_CLASS(klass) \
|
||||
(G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_MFC_DEC,GstMFCDecClass))
|
||||
#define GST_IS_MFC_DEC(obj) \
|
||||
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_MFC_DEC))
|
||||
#define GST_IS_MFC_DEC_CLASS(obj) \
|
||||
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_MFC_DEC))
|
||||
|
||||
typedef struct _GstMFCDec GstMFCDec;
|
||||
typedef struct _GstMFCDecClass GstMFCDecClass;
|
||||
|
||||
struct _GstMFCDec
|
||||
{
|
||||
GstVideoDecoder parent;
|
||||
|
||||
/* < private > */
|
||||
GstVideoCodecState *input_state;
|
||||
struct mfc_dec_context* context;
|
||||
gboolean initialized;
|
||||
GstBuffer *codec_data;
|
||||
|
||||
gboolean has_cropping;
|
||||
|
||||
GstVideoFormat format;
|
||||
FimcColorFormat fimc_format;
|
||||
Fimc *fimc;
|
||||
gint width, height;
|
||||
gint crop_left, crop_top;
|
||||
gint crop_width, crop_height;
|
||||
int src_stride[3];
|
||||
|
||||
void *dst[3];
|
||||
int dst_stride[3];
|
||||
gboolean mmap;
|
||||
};
|
||||
|
||||
struct _GstMFCDecClass
|
||||
{
|
||||
GstVideoDecoderClass parent_class;
|
||||
};
|
||||
|
||||
GType gst_mfc_dec_get_type (void);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GST_MFC_DEC_H__ */
|
|
@ -1,763 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2012 FXI Technologies
|
||||
*
|
||||
* This library is licensed under 2 different licenses and you
|
||||
* can choose to use it under the terms of any one of them. The
|
||||
* two licenses are the Apache License 2.0 and the LGPL.
|
||||
*
|
||||
* Apache License 2.0:
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* LGPL:
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* 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
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Author: Haavard Kvaalen <havardk@fxitech.com>
|
||||
*/
|
||||
|
||||
#include "mfc_decoder.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <poll.h>
|
||||
#include <pthread.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/stat.h>
|
||||
#include <linux/videodev2.h>
|
||||
|
||||
/* For logging */
|
||||
#include <gst/gst.h>
|
||||
GST_DEBUG_CATEGORY (mfc_decoder_debug);
|
||||
#define GST_CAT_DEFAULT mfc_decoder_debug
|
||||
|
||||
#define MAX_DECODER_INPUT_BUFFER_SIZE (1024 * 3072)
|
||||
#define NUM_INPUT_PLANES 1
|
||||
#define NUM_OUTPUT_PLANES 2
|
||||
#define MAX_DECODING_TIME 50
|
||||
#define MFC_PATH "/dev/video8"
|
||||
|
||||
static int mfc_in_use;
|
||||
|
||||
/* Protects the mfc_in_use variable */
|
||||
static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
struct mfc_dec_context {
|
||||
int fd;
|
||||
int num_input_buffers;
|
||||
int num_output_buffers;
|
||||
struct mfc_buffer *input_buffer;
|
||||
struct mfc_buffer *output_buffer;
|
||||
|
||||
int input_streamon, output_streamon;
|
||||
|
||||
/*
|
||||
* Number of decoded frames the MFC needs to have access to to
|
||||
* decode correctly.
|
||||
*/
|
||||
int required_output_buffers;
|
||||
int has_free_input_buffers;
|
||||
/*
|
||||
* Number of frames that have been decoded. We cannot return them
|
||||
* if this number is less than required_output_buffers.
|
||||
*/
|
||||
int output_frames_available;
|
||||
int input_frames_queued;
|
||||
/* We have reached end of stream */
|
||||
int eos_reached;
|
||||
struct {
|
||||
int w;
|
||||
int h;
|
||||
} output_size;
|
||||
struct {
|
||||
int left;
|
||||
int top;
|
||||
int w;
|
||||
int h;
|
||||
} crop_size;
|
||||
int output_stride[NUM_OUTPUT_PLANES];
|
||||
};
|
||||
|
||||
struct mfc_buffer {
|
||||
struct {
|
||||
int length;
|
||||
int bytesused;
|
||||
void *data;
|
||||
} plane[2];
|
||||
int index;
|
||||
int state;
|
||||
};
|
||||
|
||||
|
||||
enum {
|
||||
BUFFER_FREE,
|
||||
BUFFER_ENQUEUED,
|
||||
BUFFER_DEQUEUED,
|
||||
};
|
||||
|
||||
static unsigned int to_v4l2_codec(enum mfc_codec_type codec)
|
||||
{
|
||||
switch (codec) {
|
||||
case CODEC_TYPE_H264:
|
||||
return V4L2_PIX_FMT_H264;
|
||||
case CODEC_TYPE_VC1:
|
||||
return V4L2_PIX_FMT_VC1_ANNEX_G;
|
||||
case CODEC_TYPE_VC1_RCV:
|
||||
return V4L2_PIX_FMT_VC1_ANNEX_L;
|
||||
case CODEC_TYPE_MPEG4:
|
||||
return V4L2_PIX_FMT_MPEG4;
|
||||
case CODEC_TYPE_MPEG1:
|
||||
return V4L2_PIX_FMT_MPEG1;
|
||||
case CODEC_TYPE_MPEG2:
|
||||
return V4L2_PIX_FMT_MPEG2;
|
||||
case CODEC_TYPE_H263:
|
||||
return V4L2_PIX_FMT_H263;
|
||||
}
|
||||
GST_ERROR ("Invalid codec type %d", codec);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mfc_dec_set_codec(struct mfc_dec_context *ctx, enum mfc_codec_type codec)
|
||||
{
|
||||
int ret;
|
||||
struct v4l2_format fmt = {
|
||||
.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE,
|
||||
.fmt = {
|
||||
.pix_mp = {
|
||||
.num_planes = 1,
|
||||
.plane_fmt = {
|
||||
[0] = {
|
||||
.sizeimage = MAX_DECODER_INPUT_BUFFER_SIZE,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
fmt.fmt.pix_mp.pixelformat = to_v4l2_codec(codec);
|
||||
|
||||
ret = ioctl(ctx->fd, VIDIOC_S_FMT, &fmt);
|
||||
if (ret)
|
||||
GST_ERROR ("Unable to set input format");
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int request_input_buffers(struct mfc_dec_context *ctx, int num)
|
||||
{
|
||||
struct v4l2_requestbuffers reqbuf = {
|
||||
.count = num,
|
||||
.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE,
|
||||
.memory = V4L2_MEMORY_MMAP,
|
||||
};
|
||||
int i;
|
||||
|
||||
ctx->input_buffer = calloc(num, sizeof (struct mfc_buffer));
|
||||
if (!ctx->input_buffer) {
|
||||
GST_ERROR ("Failed to allocate space for input buffer meta data");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ioctl(ctx->fd, VIDIOC_REQBUFS, &reqbuf) < 0) {
|
||||
GST_ERROR ("Unable to request input buffers");
|
||||
return -1;
|
||||
}
|
||||
ctx->num_input_buffers = reqbuf.count;
|
||||
GST_INFO ("Requested %d input buffers, got %d", num, reqbuf.count);
|
||||
for (i = 0; i < num; i++) {
|
||||
void *ptr;
|
||||
struct v4l2_plane planes[NUM_INPUT_PLANES] = {{.length = 0}};
|
||||
struct v4l2_buffer buffer = {
|
||||
.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE,
|
||||
.memory = V4L2_MEMORY_MMAP,
|
||||
.index = i,
|
||||
.length = NUM_INPUT_PLANES,
|
||||
.m = {
|
||||
.planes = planes,
|
||||
},
|
||||
};
|
||||
if (ioctl(ctx->fd, VIDIOC_QUERYBUF, &buffer) < 0) {
|
||||
GST_ERROR ("Query of input buffer failed");
|
||||
return -1;
|
||||
}
|
||||
ptr = mmap(NULL, buffer.m.planes[0].length, PROT_READ | PROT_WRITE,
|
||||
MAP_SHARED, ctx->fd, buffer.m.planes[0].m.mem_offset);
|
||||
if (ptr == MAP_FAILED) {
|
||||
GST_ERROR ("Failed to map input buffer");
|
||||
return -1;
|
||||
}
|
||||
ctx->input_buffer[i].plane[0].length = planes[0].length;
|
||||
ctx->input_buffer[i].plane[0].data = ptr;
|
||||
ctx->input_buffer[i].index = i;
|
||||
ctx->input_buffer[i].state = BUFFER_FREE;
|
||||
}
|
||||
ctx->has_free_input_buffers = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int request_output_buffers(struct mfc_dec_context *ctx, int num)
|
||||
{
|
||||
struct v4l2_requestbuffers reqbuf = {
|
||||
.count = num,
|
||||
.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE,
|
||||
.memory = V4L2_MEMORY_MMAP,
|
||||
};
|
||||
int i;
|
||||
|
||||
ctx->output_buffer = calloc(num, sizeof (struct mfc_buffer));
|
||||
if (!ctx->output_buffer) {
|
||||
GST_ERROR ("Failed to allocate space for output buffer meta data");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ioctl(ctx->fd, VIDIOC_REQBUFS, &reqbuf) < 0) {
|
||||
GST_ERROR ("Unable to request output buffers");
|
||||
return -1;
|
||||
}
|
||||
ctx->num_output_buffers = reqbuf.count;
|
||||
GST_INFO ("Requested %d output buffers, got %d", num, reqbuf.count);
|
||||
for (i = 0; i < ctx->num_output_buffers; i++) {
|
||||
int p;
|
||||
struct v4l2_plane planes[NUM_OUTPUT_PLANES] = {{.length = 0}};
|
||||
struct v4l2_buffer buffer = {
|
||||
.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE,
|
||||
.memory = V4L2_MEMORY_MMAP,
|
||||
.index = i,
|
||||
.length = NUM_OUTPUT_PLANES,
|
||||
.m = {
|
||||
.planes = planes,
|
||||
},
|
||||
};
|
||||
ctx->output_buffer[i].index = i;
|
||||
if (ioctl(ctx->fd, VIDIOC_QUERYBUF, &buffer) < 0) {
|
||||
GST_ERROR ("Query of output buffer failed");
|
||||
return -1;
|
||||
}
|
||||
for (p = 0; p < NUM_OUTPUT_PLANES; p++) {
|
||||
void *ptr = mmap(NULL, buffer.m.planes[p].length,
|
||||
PROT_READ | PROT_WRITE, MAP_SHARED,
|
||||
ctx->fd, buffer.m.planes[p].m.mem_offset);
|
||||
if (ptr == MAP_FAILED) {
|
||||
GST_ERROR ("Failed to map output buffer");
|
||||
return -1;
|
||||
}
|
||||
ctx->output_buffer[i].plane[p].length = planes[p].length;
|
||||
ctx->output_buffer[i].plane[p].data = ptr;
|
||||
}
|
||||
if (mfc_dec_enqueue_output(ctx, &ctx->output_buffer[i]) < 0)
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct mfc_dec_context* mfc_dec_create(unsigned int codec)
|
||||
{
|
||||
struct mfc_dec_context *ctx;
|
||||
struct v4l2_capability caps;
|
||||
struct stat sb;
|
||||
|
||||
pthread_mutex_lock(&mutex);
|
||||
if (mfc_in_use) {
|
||||
GST_ERROR ("Rejected because MFC is already in use");
|
||||
pthread_mutex_unlock(&mutex);
|
||||
return NULL;
|
||||
}
|
||||
mfc_in_use = 1;
|
||||
pthread_mutex_unlock(&mutex);
|
||||
|
||||
ctx = calloc(1, sizeof (struct mfc_dec_context));
|
||||
if (!ctx) {
|
||||
GST_ERROR ("Unable to allocate memory for context");
|
||||
goto early_error;
|
||||
}
|
||||
ctx->output_frames_available = 0;
|
||||
|
||||
if (stat (MFC_PATH, &sb) < 0) {
|
||||
GST_INFO ("MFC device node doesn't exist, failing quietly");
|
||||
free(ctx);
|
||||
goto early_error;
|
||||
}
|
||||
|
||||
GST_INFO ("Opening MFC device node at: %s", MFC_PATH);
|
||||
ctx->fd = open(MFC_PATH, O_RDWR, 0);
|
||||
if (ctx->fd == -1) {
|
||||
GST_WARNING ("Unable to open MFC device node: %d", errno);
|
||||
free(ctx);
|
||||
goto early_error;
|
||||
}
|
||||
|
||||
if (ioctl (ctx->fd, VIDIOC_QUERYCAP, &caps) < 0) {
|
||||
GST_ERROR ("Unable to query capabilities: %d", errno);
|
||||
mfc_dec_destroy(ctx);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ((caps.capabilities & V4L2_CAP_STREAMING) == 0 ||
|
||||
(caps.capabilities & V4L2_CAP_VIDEO_OUTPUT_MPLANE) == 0 ||
|
||||
(caps.capabilities & V4L2_CAP_VIDEO_CAPTURE_MPLANE) == 0) {
|
||||
GST_ERROR ("Required capabilities not available");
|
||||
mfc_dec_destroy(ctx);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (mfc_dec_set_codec(ctx, codec) < 0) {
|
||||
mfc_dec_destroy(ctx);
|
||||
return NULL;
|
||||
}
|
||||
return ctx;
|
||||
|
||||
early_error:
|
||||
pthread_mutex_lock(&mutex);
|
||||
mfc_in_use = 0;
|
||||
pthread_mutex_unlock(&mutex);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int get_output_format(struct mfc_dec_context *ctx)
|
||||
{
|
||||
int i;
|
||||
struct v4l2_format fmt = {
|
||||
.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE,
|
||||
};
|
||||
|
||||
if (ioctl(ctx->fd, VIDIOC_G_FMT, &fmt) < 0) {
|
||||
GST_ERROR ("Failed to get output format");
|
||||
return -1;
|
||||
}
|
||||
|
||||
ctx->output_size.w = fmt.fmt.pix_mp.width;
|
||||
ctx->output_size.h = fmt.fmt.pix_mp.height;
|
||||
|
||||
for (i = 0; i < NUM_OUTPUT_PLANES; i++)
|
||||
ctx->output_stride[i] = fmt.fmt.pix_mp.plane_fmt[i].bytesperline;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int get_crop_data(struct mfc_dec_context *ctx)
|
||||
{
|
||||
struct v4l2_crop crop = {
|
||||
.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE,
|
||||
};
|
||||
if (ioctl(ctx->fd, VIDIOC_G_CROP, &crop) < 0) {
|
||||
GST_ERROR ("Unable to get crop data");
|
||||
return -1;
|
||||
}
|
||||
ctx->crop_size.left = crop.c.left;
|
||||
ctx->crop_size.top = crop.c.top;
|
||||
ctx->crop_size.w = crop.c.width;
|
||||
ctx->crop_size.h = crop.c.height;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int get_minimum_output_buffers(struct mfc_dec_context *ctx)
|
||||
{
|
||||
struct v4l2_control ctrl = {
|
||||
.id = V4L2_CID_MIN_BUFFERS_FOR_CAPTURE,
|
||||
};
|
||||
if (ioctl(ctx->fd, VIDIOC_G_CTRL, &ctrl) < 0) {
|
||||
GST_ERROR ("Failed to get number of output buffers required");
|
||||
return -1;
|
||||
}
|
||||
ctx->required_output_buffers = ctrl.value + 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int start_input_stream(struct mfc_dec_context *ctx)
|
||||
{
|
||||
int type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
|
||||
if (ioctl(ctx->fd, VIDIOC_STREAMON, &type) < 0) {
|
||||
GST_ERROR ("Unable to start input stream");
|
||||
return -1;
|
||||
}
|
||||
ctx->input_streamon = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int start_output_stream(struct mfc_dec_context *ctx)
|
||||
{
|
||||
int type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
|
||||
if (ioctl(ctx->fd, VIDIOC_STREAMON, &type) < 0) {
|
||||
GST_ERROR ("Unable to start output stream");
|
||||
return -1;
|
||||
}
|
||||
ctx->output_streamon = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mfc_dec_init_input(struct mfc_dec_context *ctx, int num_input_buffers)
|
||||
{
|
||||
if (request_input_buffers(ctx, num_input_buffers) < 0)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mfc_dec_init_output(struct mfc_dec_context *ctx, int extra_buffers)
|
||||
{
|
||||
if (start_input_stream(ctx) < 0)
|
||||
return -1;
|
||||
|
||||
if (get_output_format(ctx) ||
|
||||
get_crop_data(ctx) ||
|
||||
get_minimum_output_buffers(ctx))
|
||||
return -1;
|
||||
|
||||
if (request_output_buffers(ctx, ctx->required_output_buffers + extra_buffers))
|
||||
return -1;
|
||||
|
||||
if (start_output_stream(ctx) < 0)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void mfc_dec_get_output_size(struct mfc_dec_context *ctx, int *w, int *h)
|
||||
{
|
||||
*w = ctx->output_size.w;
|
||||
*h = ctx->output_size.h;
|
||||
}
|
||||
|
||||
void mfc_dec_get_output_stride(struct mfc_dec_context *ctx, int *ystride, int *uvstride)
|
||||
{
|
||||
*ystride = ctx->output_stride[0];
|
||||
*uvstride = ctx->output_stride[1];
|
||||
}
|
||||
|
||||
void mfc_dec_get_crop_size(struct mfc_dec_context *ctx,
|
||||
int *left, int *top, int *w, int *h)
|
||||
{
|
||||
*left = ctx->crop_size.left;
|
||||
*top = ctx->crop_size.top;
|
||||
*w = ctx->crop_size.w;
|
||||
*h = ctx->crop_size.h;
|
||||
}
|
||||
|
||||
void mfc_dec_destroy(struct mfc_dec_context *ctx)
|
||||
{
|
||||
int i;
|
||||
int type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
|
||||
|
||||
if (ctx->output_streamon)
|
||||
if (ioctl(ctx->fd, VIDIOC_STREAMOFF, &type) < 0)
|
||||
GST_ERROR ("Streamoff failed on output");
|
||||
ctx->output_streamon = 0;
|
||||
|
||||
type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
|
||||
if (ctx->input_streamon)
|
||||
if (ioctl(ctx->fd, VIDIOC_STREAMOFF, &type) < 0)
|
||||
GST_ERROR ("Streamoff failed on input");
|
||||
ctx->input_streamon = 0;
|
||||
|
||||
for (i = 0; i < ctx->num_input_buffers; i++) {
|
||||
if (ctx->input_buffer[i].plane[0].data)
|
||||
munmap(ctx->input_buffer[i].plane[0].data,
|
||||
ctx->input_buffer[i].plane[0].length);
|
||||
}
|
||||
for (i = 0; i < ctx->num_output_buffers; i++) {
|
||||
int j;
|
||||
for (j = 0; j < NUM_OUTPUT_PLANES; j++)
|
||||
if (ctx->output_buffer[i].plane[j].data)
|
||||
munmap(ctx->output_buffer[i].plane[j].data,
|
||||
ctx->output_buffer[i].plane[j].length);
|
||||
}
|
||||
if (ctx->input_buffer)
|
||||
free (ctx->input_buffer);
|
||||
if (ctx->output_buffer)
|
||||
free (ctx->output_buffer);
|
||||
|
||||
close(ctx->fd);
|
||||
pthread_mutex_lock(&mutex);
|
||||
mfc_in_use = 0;
|
||||
pthread_mutex_unlock(&mutex);
|
||||
GST_INFO ("MFC device closed");
|
||||
free(ctx);
|
||||
}
|
||||
|
||||
int mfc_dec_enqueue_input(struct mfc_dec_context *ctx, struct mfc_buffer *buffer, struct timeval *timestamp)
|
||||
{
|
||||
struct v4l2_plane planes[NUM_INPUT_PLANES] = {
|
||||
[0] = {
|
||||
.bytesused = buffer->plane[0].bytesused,
|
||||
},
|
||||
};
|
||||
struct v4l2_buffer qbuf = {
|
||||
.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE,
|
||||
.memory = V4L2_MEMORY_MMAP,
|
||||
.index = buffer->index,
|
||||
.length = NUM_INPUT_PLANES,
|
||||
.m = {
|
||||
.planes = planes,
|
||||
},
|
||||
};
|
||||
|
||||
if (timestamp)
|
||||
qbuf.timestamp = *timestamp;
|
||||
|
||||
if (ioctl(ctx->fd, VIDIOC_QBUF, &qbuf) < 0) {
|
||||
GST_ERROR ("Enqueuing of input buffer %d failed; prev state: %d",
|
||||
buffer->index, buffer->state);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ctx->input_frames_queued++;
|
||||
buffer->state = BUFFER_ENQUEUED;
|
||||
if (buffer->plane[0].bytesused == 0)
|
||||
ctx->eos_reached = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int input_dqbuf(struct mfc_dec_context *ctx, struct mfc_buffer **buffer)
|
||||
{
|
||||
struct v4l2_plane planes[NUM_INPUT_PLANES] = {{.length = 0}};
|
||||
struct v4l2_buffer qbuf = {
|
||||
.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE,
|
||||
.memory = V4L2_MEMORY_MMAP,
|
||||
.length = NUM_INPUT_PLANES,
|
||||
.m = {
|
||||
.planes = planes,
|
||||
}
|
||||
};
|
||||
struct pollfd fd = {
|
||||
.fd = ctx->fd,
|
||||
.events = POLLOUT | POLLERR,
|
||||
};
|
||||
int pollret;
|
||||
|
||||
pollret = poll(&fd, 1, MAX_DECODING_TIME);
|
||||
if (pollret < 0) {
|
||||
GST_ERROR ("%s: Poll returned error: %d", __func__, errno);
|
||||
return -1;
|
||||
}
|
||||
if (pollret == 0) {
|
||||
GST_INFO ("%s: timed out", __func__);
|
||||
return -2;
|
||||
}
|
||||
|
||||
if (ioctl(ctx->fd, VIDIOC_DQBUF, &qbuf) < 0) {
|
||||
GST_ERROR ("Dequeuing failed");
|
||||
return -1;
|
||||
}
|
||||
ctx->input_buffer[qbuf.index].plane[0].bytesused = 0;
|
||||
*buffer = &ctx->input_buffer[qbuf.index];
|
||||
ctx->output_frames_available++;
|
||||
ctx->input_frames_queued--;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mfc_dec_dequeue_input(struct mfc_dec_context *ctx, struct mfc_buffer **buffer)
|
||||
{
|
||||
if (ctx->has_free_input_buffers) {
|
||||
int i;
|
||||
*buffer = NULL;
|
||||
for (i = 0; i < ctx->num_input_buffers; i++) {
|
||||
if (ctx->input_buffer[i].state == BUFFER_FREE)
|
||||
*buffer = &ctx->input_buffer[i];
|
||||
}
|
||||
if (!*buffer) {
|
||||
int ret;
|
||||
ctx->has_free_input_buffers = 0;
|
||||
if ((ret = input_dqbuf(ctx, buffer)) < 0)
|
||||
return ret;
|
||||
}
|
||||
} else {
|
||||
int ret = input_dqbuf(ctx, buffer);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
(*buffer)->state = BUFFER_DEQUEUED;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int release_input_buffer(struct mfc_dec_context *ctx)
|
||||
{
|
||||
struct mfc_buffer *buffer;
|
||||
struct pollfd fd = {
|
||||
.fd = ctx->fd,
|
||||
.events = POLLOUT | POLLERR,
|
||||
};
|
||||
int pollret;
|
||||
|
||||
if (ctx->input_frames_queued == 0) {
|
||||
GST_INFO ("Nothing to release!");
|
||||
return -1;
|
||||
}
|
||||
|
||||
pollret = poll(&fd, 1, MAX_DECODING_TIME);
|
||||
if (pollret < 0) {
|
||||
GST_ERROR ("%s: Poll returned error: %d", __func__, errno);
|
||||
return -1;
|
||||
}
|
||||
if (pollret == 0) {
|
||||
GST_INFO ("%s: timed out", __func__);
|
||||
return -2;
|
||||
}
|
||||
|
||||
GST_DEBUG ("releasing frame; frames queued: %d", ctx->input_frames_queued);
|
||||
input_dqbuf(ctx, &buffer);
|
||||
buffer->state = BUFFER_FREE;
|
||||
ctx->has_free_input_buffers = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mfc_dec_enqueue_output(struct mfc_dec_context *ctx, struct mfc_buffer *buffer)
|
||||
{
|
||||
struct v4l2_plane planes[NUM_OUTPUT_PLANES] = {{.length = 0}};
|
||||
struct v4l2_buffer qbuf = {
|
||||
.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE,
|
||||
.memory = V4L2_MEMORY_MMAP,
|
||||
.index = buffer->index,
|
||||
.length = NUM_OUTPUT_PLANES,
|
||||
.m = {
|
||||
.planes = planes,
|
||||
},
|
||||
};
|
||||
if (ioctl(ctx->fd, VIDIOC_QBUF, &qbuf) < 0) {
|
||||
GST_ERROR ("Enqueuing of output buffer %d failed; prev state: %d",
|
||||
buffer->index, buffer->state);
|
||||
return -1;
|
||||
}
|
||||
buffer->state = BUFFER_ENQUEUED;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mfc_dec_dequeue_output(struct mfc_dec_context *ctx, struct mfc_buffer **buffer, struct timeval *timestamp)
|
||||
{
|
||||
int i;
|
||||
struct v4l2_plane planes[NUM_OUTPUT_PLANES];
|
||||
struct v4l2_buffer qbuf = {
|
||||
.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE,
|
||||
.memory = V4L2_MEMORY_MMAP,
|
||||
.m = {
|
||||
.planes = planes,
|
||||
},
|
||||
.length = NUM_OUTPUT_PLANES,
|
||||
};
|
||||
|
||||
if (ioctl(ctx->fd, VIDIOC_DQBUF, &qbuf) < 0) {
|
||||
GST_ERROR ("Dequeuing failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (i = 0; i < NUM_OUTPUT_PLANES; i++)
|
||||
ctx->output_buffer[qbuf.index].plane[i].bytesused = qbuf.m.planes[i].bytesused;
|
||||
|
||||
*buffer = &(ctx->output_buffer[qbuf.index]);
|
||||
|
||||
if (timestamp)
|
||||
*timestamp = qbuf.timestamp;
|
||||
|
||||
ctx->output_frames_available--;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mfc_dec_output_available(struct mfc_dec_context *ctx)
|
||||
{
|
||||
if (ctx->eos_reached) {
|
||||
if (ctx->input_frames_queued > 0 &&
|
||||
ctx->output_frames_available <= ctx->required_output_buffers) {
|
||||
release_input_buffer(ctx);
|
||||
}
|
||||
|
||||
return ctx->output_frames_available > 0;
|
||||
}
|
||||
return ctx->output_frames_available >= ctx->required_output_buffers;
|
||||
}
|
||||
|
||||
int mfc_dec_flush(struct mfc_dec_context *ctx)
|
||||
{
|
||||
int type, i;
|
||||
int force_dequeue_output = 0;
|
||||
while (ctx->input_frames_queued > 0) {
|
||||
int status;
|
||||
struct mfc_buffer *buffer;
|
||||
/* Make sure there is room for the decode to finish */
|
||||
if (mfc_dec_output_available(ctx) || force_dequeue_output) {
|
||||
if (mfc_dec_dequeue_output(ctx, &buffer, NULL) < 0)
|
||||
return -1;
|
||||
if (mfc_dec_enqueue_output(ctx, buffer) < 0)
|
||||
return -1;
|
||||
force_dequeue_output = 0;
|
||||
}
|
||||
|
||||
status = release_input_buffer(ctx);
|
||||
if (status == -2)
|
||||
force_dequeue_output = 1;
|
||||
if (status == -1)
|
||||
break;
|
||||
}
|
||||
|
||||
type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
|
||||
if (ioctl(ctx->fd, VIDIOC_STREAMOFF, &type) < 0) {
|
||||
GST_ERROR ("Unable to stop output stream");
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (i = 0; i < ctx->num_output_buffers; i++) {
|
||||
if (ctx->output_buffer[i].state == BUFFER_ENQUEUED)
|
||||
if (mfc_dec_enqueue_output(ctx, &ctx->output_buffer[i]) < 0)
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (start_output_stream(ctx) < 0)
|
||||
return -1;
|
||||
|
||||
ctx->output_frames_available = 0;
|
||||
ctx->eos_reached = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void* mfc_buffer_get_input_data(struct mfc_buffer *buffer)
|
||||
{
|
||||
return buffer->plane[0].data;
|
||||
}
|
||||
|
||||
int mfc_buffer_get_input_max_size(struct mfc_buffer *buffer)
|
||||
{
|
||||
return buffer->plane[0].length;
|
||||
}
|
||||
|
||||
|
||||
void mfc_buffer_set_input_size(struct mfc_buffer *buffer, int size)
|
||||
{
|
||||
buffer->plane[0].bytesused = size;
|
||||
}
|
||||
|
||||
void mfc_buffer_get_output_data(struct mfc_buffer *buffer,
|
||||
void **ybuf, void **uvbuf)
|
||||
{
|
||||
*ybuf = buffer->plane[0].data;
|
||||
*uvbuf = buffer->plane[1].data;
|
||||
}
|
||||
|
||||
void mfc_dec_init_debug (void)
|
||||
{
|
||||
GST_DEBUG_CATEGORY_INIT (mfc_decoder_debug, "mfc_decoder", 0, "MFC decoder library");
|
||||
}
|
|
@ -1,218 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2012 FXI Technologies
|
||||
*
|
||||
* This library is licensed under 2 different licenses and you
|
||||
* can choose to use it under the terms of any one of them. The
|
||||
* two licenses are the Apache License 2.0 and the LGPL.
|
||||
*
|
||||
* Apache License 2.0:
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* LGPL:
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* 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
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
/*
|
||||
* Author: Haavard Kvaalen <havardk@fxitech.com>
|
||||
*/
|
||||
|
||||
/*
|
||||
* Interface for decoding of various video formats using the Samsung
|
||||
* Multi-Format Video Codec (MFC).
|
||||
*/
|
||||
|
||||
#ifndef VIDEO_EXYNOS4_MFC_V4L2_INCLUDE_MFC_DECODER_H
|
||||
#define VIDEO_EXYNOS4_MFC_V4L2_INCLUDE_MFC_DECODER_H
|
||||
|
||||
#include <sys/time.h>
|
||||
|
||||
struct mfc_buffer;
|
||||
struct mfc_dec_context;
|
||||
|
||||
enum mfc_codec_type {
|
||||
CODEC_TYPE_H264,
|
||||
CODEC_TYPE_VC1, /* VC1 advanced profile */
|
||||
CODEC_TYPE_VC1_RCV, /* VC1 simple/main profile */
|
||||
CODEC_TYPE_MPEG4,
|
||||
CODEC_TYPE_MPEG1,
|
||||
CODEC_TYPE_MPEG2,
|
||||
CODEC_TYPE_H263,
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void mfc_dec_init_debug (void);
|
||||
|
||||
/*
|
||||
* Open the MFC decoding device node, and allocate input buffers.
|
||||
*
|
||||
* Returns a mfc_dec_context. Note that the context can only be used
|
||||
* for decoding one stream, i.e. mfc_dec_init can only be called once.
|
||||
*
|
||||
* Args:
|
||||
* codec: Codec type (this can later be changed with mfc_set_codec()).
|
||||
* num_input_buffers: Numbers of input buffers. There is never any
|
||||
* need to enqueue more than one buffer for correct decoding.
|
||||
*
|
||||
* Returns: A new mfc_dec_context if successful, NULL on error. This
|
||||
* context is needed for most other calls below, and should be
|
||||
* deallocated with mfc_dec_destroy().
|
||||
*/
|
||||
struct mfc_dec_context* mfc_dec_create(enum mfc_codec_type codec);
|
||||
|
||||
int mfc_dec_init_input(struct mfc_dec_context*, int num_input_buffers);
|
||||
|
||||
/*
|
||||
* Destroy context created with mfc_dec_create().
|
||||
*/
|
||||
void mfc_dec_destroy(struct mfc_dec_context*);
|
||||
|
||||
/*
|
||||
* Initialize video decode. Before this function is called, the
|
||||
* initial input frame (which contains the header) must be enqueued.
|
||||
*
|
||||
* This function allocate output buffers. All output buffers will be
|
||||
* enqueued initially. The actual number of output buffers depend on the
|
||||
*
|
||||
* Args:
|
||||
* extra_buffers: Numbers of output buffers that can be kept
|
||||
* dequeued at any time.
|
||||
*
|
||||
* Returns: Zero for success, negative value on failure.
|
||||
*/
|
||||
int mfc_dec_init_output(struct mfc_dec_context*, int extra_buffers);
|
||||
|
||||
|
||||
/*
|
||||
* This function may be called only before mfc_dec_init(). It is only
|
||||
* necessary to call if the codec type is different from the one
|
||||
* supplied to mfc_dec_create().
|
||||
*
|
||||
* Args:
|
||||
* codec: Codec type
|
||||
*
|
||||
* Returns: Zero for success, negative value on failure.
|
||||
*/
|
||||
int mfc_dec_set_codec(struct mfc_dec_context*, enum mfc_codec_type codec);
|
||||
|
||||
|
||||
/*
|
||||
* Get size of image output from the MFC. The data might be larger
|
||||
* than the actual video because of MFC alignment requirements (see
|
||||
* the crop size below). This function can only be called after
|
||||
* mfc_dec_init() has been called.
|
||||
*
|
||||
* Args:
|
||||
* w: Width (output).
|
||||
* h: Height (output).
|
||||
*
|
||||
* Returns: Zero for success, negative value on failure.
|
||||
*/
|
||||
void mfc_dec_get_output_size(struct mfc_dec_context*, int *w, int *h);
|
||||
void mfc_dec_get_output_stride(struct mfc_dec_context*, int *ystride, int *uvstride);
|
||||
void mfc_dec_get_crop_size(struct mfc_dec_context*,
|
||||
int *left, int *top, int *w, int *h);
|
||||
|
||||
/*
|
||||
* Check if there are output frames that can be dequeued.
|
||||
*
|
||||
* Returns: Positive value if a frame is available, zero if not.
|
||||
*/
|
||||
int mfc_dec_output_available(struct mfc_dec_context*);
|
||||
|
||||
/*
|
||||
* This module use 'input' and 'output' for input to, and output from
|
||||
* the MFC. The VFL2 names for these interfaces are OUTPUT (for the
|
||||
* input) and CAPTURE (for the output).
|
||||
*
|
||||
* These functions return zero for success, negative value on failure.
|
||||
*
|
||||
* When the end of stream has been reached, an empty input frame
|
||||
* should be enqueued after the last valid input frame. This signal
|
||||
* to the MFC that EOS has been reached. After this no more input
|
||||
* frames can be enqueued.
|
||||
*/
|
||||
|
||||
/* Enqueue frame containing compressed data */
|
||||
int mfc_dec_enqueue_input(struct mfc_dec_context*, struct mfc_buffer *buffer, struct timeval *timestamp);
|
||||
/*
|
||||
* Dequeue a processed input frame. Will block until one is available.
|
||||
*
|
||||
* Returns 0 on success, -1 on failure, and -2 on timeout. A timeout
|
||||
* typically happens if there are no free output buffers available.
|
||||
*/
|
||||
int mfc_dec_dequeue_input(struct mfc_dec_context*, struct mfc_buffer **buffer);
|
||||
/* Enqueue empty output frame */
|
||||
int mfc_dec_enqueue_output(struct mfc_dec_context*, struct mfc_buffer *buffer);
|
||||
/*
|
||||
* Dequeue output frame with image data. This should only be called
|
||||
* when mfc_dec_output_available() returns true. If this is called
|
||||
* when mfc_dec_output_available() is not true, subsequent video
|
||||
* frames may not decode correctly.
|
||||
*/
|
||||
int mfc_dec_dequeue_output(struct mfc_dec_context*, struct mfc_buffer **buffer, struct timeval *timestamp);
|
||||
|
||||
|
||||
/*
|
||||
* Flush (discard) all enqueued output and input frames. This is
|
||||
* typically used if we want to seek.
|
||||
*
|
||||
* Calling flush resets the "end of stream" state that is entered by
|
||||
* enqueuing an empty input frame. Thus it is safe to seek at the end
|
||||
* of the stream as long as mfc_dec_flush() is called first.
|
||||
*/
|
||||
int mfc_dec_flush(struct mfc_dec_context*);
|
||||
|
||||
/*
|
||||
* Get pointer to the input data in 'buffer'.
|
||||
*/
|
||||
void* mfc_buffer_get_input_data(struct mfc_buffer *buffer);
|
||||
|
||||
/*
|
||||
* Get maximum size of input buffer 'buffer' in bytes.
|
||||
*/
|
||||
int mfc_buffer_get_input_max_size(struct mfc_buffer *buffer);
|
||||
|
||||
/*
|
||||
* Set size of data that has been put into 'buffer' in bytes.
|
||||
*/
|
||||
void mfc_buffer_set_input_size(struct mfc_buffer *buffer, int size);
|
||||
|
||||
/*
|
||||
* Get pointers to data in output buffer 'buffer'.
|
||||
*/
|
||||
void mfc_buffer_get_output_data(struct mfc_buffer *buffer,
|
||||
void **ybuf, void **uvbuf);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#endif /* VIDEO_EXYNOS4_MFC_V4L2_INCLUDE_MFC_DECODER_H */
|
Loading…
Reference in a new issue