From da521d4e1315199a5fb781adf8a56efdc64c2b42 Mon Sep 17 00:00:00 2001
From: yhe <yhe@matrox.com>
Date: Wed, 27 Mar 2019 11:05:41 -0400
Subject: [PATCH] h.264 decoder and encoder support with M264
---
Changelog | 1 +
configure | 2 +
libavcodec/Makefile | 2 +
libavcodec/allcodecs.c | 2 +
libavcodec/m264dec.c | 357 +++++++++++++++++++++++++++++++++++++++++++++++++
libavcodec/m264dec.h | 40 ++++++
libavcodec/m264enc.c | 335 ++++++++++++++++++++++++++++++++++++++++++++++
libavcodec/m264enc.h | 38 ++++++
8 files changed, 777 insertions(+)
create mode 100644 libavcodec/m264dec.c
create mode 100644 libavcodec/m264dec.h
create mode 100644 libavcodec/m264enc.c
create mode 100644 libavcodec/m264enc.h
@@ -19,6 +19,7 @@ version <next>:
- ARBC decoder
- libaribb24 based ARIB STD-B24 caption support (profiles A and C)
- Support decoding of HEVC 4:4:4 content in nvdec and cuviddec
+- Support h.264 encoding and decoding with Matrox M264 card.
version 4.1:
@@ -2697,6 +2697,8 @@ h263p_decoder_select="h263_decoder"
h263p_encoder_select="h263_encoder"
h264_decoder_select="cabac golomb h264chroma h264dsp h264parse h264pred h264qpel videodsp"
h264_decoder_suggest="error_resilience"
+h264_m264_decoder_deps_any="libdl"
+h264_m264_encoder_deps_any="libdl libswscale"
hap_decoder_select="snappy texturedsp"
hap_encoder_deps="libsnappy"
hap_encoder_select="texturedspenc"
@@ -348,6 +348,8 @@ OBJS-$(CONFIG_H264_DECODER) += h264dec.o h264_cabac.o h264_cavlc.o \
h264_slice.o h264data.o
OBJS-$(CONFIG_H264_AMF_ENCODER) += amfenc_h264.o
OBJS-$(CONFIG_H264_CUVID_DECODER) += cuviddec.o
+OBJS-$(CONFIG_H264_M264_DECODER) += m264dec.o
+OBJS-$(CONFIG_H264_M264_ENCODER) += m264enc.o
OBJS-$(CONFIG_H264_MEDIACODEC_DECODER) += mediacodecdec.o
OBJS-$(CONFIG_H264_MMAL_DECODER) += mmaldec.o
OBJS-$(CONFIG_H264_NVENC_ENCODER) += nvenc_h264.o
@@ -737,6 +737,8 @@ extern AVCodec ff_libopenh264_encoder;
extern AVCodec ff_libopenh264_decoder;
extern AVCodec ff_h264_amf_encoder;
extern AVCodec ff_h264_cuvid_decoder;
+extern AVCodec ff_h264_m264_decoder;
+extern AVCodec ff_h264_m264_encoder;
extern AVCodec ff_h264_nvenc_encoder;
extern AVCodec ff_h264_omx_encoder;
extern AVCodec ff_h264_qsv_encoder;
new file mode 100644
@@ -0,0 +1,357 @@
+/*
+ * M264 H.264 video decoder
+ *
+ * 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
+ */
+
+/**
+ * @file
+ * Matrox M264 card supports h.264 encoding and decoding.
+ */
+
+#include "decode.h"
+#include "cabac.h"
+#include "error_resilience.h"
+#include "h264_parse.h"
+#include "h264_ps.h"
+#include "h264_sei.h"
+#include "h2645_parse.h"
+#include "h264chroma.h"
+#include "h264dsp.h"
+#include "h264pred.h"
+#include "h264qpel.h"
+#include "internal.h"
+#include "mpegutils.h"
+#include "parser.h"
+#include "qpeldsp.h"
+#include "rectangle.h"
+#include "videodsp.h"
+#include "config.h"
+#include "libswscale/swscale.h"
+#include "libavutil/opt.h"
+#include "m264dec.h"
+#ifdef _WIN32
+#include "compat/w32dlfcn.h"
+#else
+#include <dlfcn.h>
+#endif
+
+typedef struct {
+ uint16_t input_width;
+ uint16_t input_height;
+ uint16_t output_width;
+ uint16_t output_height;
+ uint16_t scale;
+ uint16_t rate;
+ uint16_t gop_size;
+ uint32_t bitrate;
+ uint8_t field_order;
+} M264DecoderInfo;
+
+typedef struct {
+ AVClass *class;
+ int (*init_m264_decoder)(void *decoder_info, void **m264_decoder_object);
+ int (*exit_m264_decoder)(void *m264_decoder_object);
+ int (*send_packet)(void *m264_decoder_object, void *extradata, unsigned long extradata_size, void *buffer, unsigned long buffer_size, double duration);
+ int (*receive_frame)(void *m264_decoder_object, void **buffer_context, void **buffer, unsigned long *buffer_size);
+ int (*release_frame_buffer)(void *m264_decoder_object, void *buffer_context);
+ void *lib_handle;
+ void *decoder_context;
+ int64_t frames;
+ int eof;
+ char *sps_pps;
+ int length_sps_pps;
+ AVBSFContext *ctx;
+ char *resize_expr;
+ struct {
+ int width;
+ int height;
+ } resize;
+} M264DecoderContext;
+
+int m264_mp4_to_annexb(AVCodecContext *avctx, AVPacket *packet)
+{
+ M264DecoderContext *m264_decoder_context = (M264DecoderContext *)avctx->priv_data;
+ int ret = 0;
+
+ if (m264_decoder_context->ctx) {
+ ret = av_bsf_send_packet(m264_decoder_context->ctx, packet);
+ if (ret < 0)
+ return ret;
+
+ ret = av_bsf_receive_packet(m264_decoder_context->ctx, packet);
+ if (ret < 0)
+ return ret;
+ }
+
+ return ret;
+}
+
+int m264_init_spspps_mp4(AVCodecContext *avctx)
+{
+ M264DecoderContext *m264_decoder_context = (M264DecoderContext *)avctx->priv_data;
+ int ret = 0;
+ const AVBitStreamFilter *filter = av_bsf_get_by_name("h264_mp4toannexb");
+ AVBSFContext *ctx = NULL;
+
+ ret = av_bsf_alloc(filter, &ctx);
+ if (ret < 0)
+ return ret;
+
+ ret = avcodec_parameters_from_context(ctx->par_in, avctx);
+ if (ret < 0)
+ return ret;
+
+ ret = av_bsf_init(ctx);
+ if (ret < 0)
+ return ret;
+
+ m264_decoder_context->ctx = ctx;
+
+ if (ctx->par_out->extradata_size > 0) {
+ m264_decoder_context->sps_pps = av_mallocz(ctx->par_out->extradata_size);
+ memcpy(m264_decoder_context->sps_pps, ctx->par_out->extradata, ctx->par_out->extradata_size);
+ m264_decoder_context->length_sps_pps = ctx->par_out->extradata_size;
+ }
+
+ return ret;
+}
+
+av_cold int ff_m264_decode_init(AVCodecContext *avctx)
+{
+ int ret = 0;
+ void *lib_handle;
+ M264DecoderContext *m264_decoder_context;
+ M264DecoderInfo decoder_info;
+
+ #ifdef _WIN32
+ lib_handle = dlopen("mvM264.dll", RTLD_LAZY);
+ #else
+ lib_handle = dlopen("libmvM264.so", RTLD_LAZY);
+ #endif
+
+ if (!lib_handle) {
+ av_log(avctx, AV_LOG_ERROR, "failed to load mvM264\n");
+ return AVERROR_DECODER_NOT_FOUND;
+ }
+
+ m264_decoder_context = avctx->priv_data;
+
+ m264_decoder_context->init_m264_decoder = dlsym(lib_handle, "m264_decoder_init");
+ if (!m264_decoder_context->init_m264_decoder) {
+ av_log(avctx, AV_LOG_ERROR, "failed to load mvM264\n");
+ return AVERROR_DECODER_NOT_FOUND;
+ }
+
+ m264_decoder_context->exit_m264_decoder = dlsym(lib_handle, "m264_decoder_exit");
+ if (!m264_decoder_context->exit_m264_decoder) {
+ av_log(avctx, AV_LOG_ERROR, "failed to load mvM264\n");
+ return AVERROR_DECODER_NOT_FOUND;
+ }
+
+ m264_decoder_context->send_packet = dlsym(lib_handle, "m264_decoder_send_packet");
+ if (!m264_decoder_context->send_packet) {
+ av_log(avctx, AV_LOG_ERROR, "failed to load mvM264\n");
+ return AVERROR_DECODER_NOT_FOUND;
+ }
+
+ m264_decoder_context->receive_frame = dlsym(lib_handle, "m264_decoder_receive_frame");
+ if (!m264_decoder_context->receive_frame) {
+ av_log(avctx, AV_LOG_ERROR, "failed to load mvM264\n");
+ return AVERROR_DECODER_NOT_FOUND;
+ }
+
+ m264_decoder_context->release_frame_buffer = dlsym(lib_handle, "m264_decoder_release_frame_buffer");
+ if (!m264_decoder_context->release_frame_buffer) {
+ av_log(avctx, AV_LOG_ERROR, "failed to load mvM264\n");
+ return AVERROR_DECODER_NOT_FOUND;
+ }
+
+ m264_decoder_context->lib_handle = lib_handle;
+ m264_decoder_context->eof = 0;
+
+ decoder_info.input_width = avctx->width;
+ decoder_info.input_height = avctx->height;
+
+ if (m264_decoder_context->resize_expr) {
+ if (sscanf(m264_decoder_context->resize_expr, "%dx%d", &m264_decoder_context->resize.width, &m264_decoder_context->resize.height) != 2) {
+ av_log(avctx, AV_LOG_ERROR, "Invalid resize expressions\n");
+ m264_decoder_context->resize.width = avctx->width;
+ m264_decoder_context->resize.height = avctx->height;
+ }
+
+ if (m264_decoder_context->resize.height == -1)
+ m264_decoder_context->resize.height = (float)m264_decoder_context->resize.width * avctx->height / avctx->width;
+
+ avctx->width = m264_decoder_context->resize.width;
+ avctx->height = m264_decoder_context->resize.height;
+ }
+
+ decoder_info.output_width = avctx->width;
+ decoder_info.output_height = avctx->height;
+ decoder_info.scale = avctx->framerate.den;
+ decoder_info.rate = avctx->framerate.num;
+ decoder_info.field_order = (uint8_t)avctx->field_order;
+ av_log(avctx, AV_LOG_DEBUG, "m264_decode_init_h264: avctx->field_order is %d \n", avctx->field_order);
+ av_log(avctx, AV_LOG_DEBUG, "m264_decode_init_h264: avctx->width = %d, avctx->height = %d, avctx->framerate.num = %d, avctx->framerate.den = %d\n",
+ avctx->width, avctx->height, avctx->framerate.num, avctx->framerate.den);
+
+ ret = m264_decoder_context->init_m264_decoder(&decoder_info, &(m264_decoder_context->decoder_context));
+ if (ret < 0)
+ return ret;
+
+ avctx->priv_data = m264_decoder_context;
+ avctx->pix_fmt = AV_PIX_FMT_YUYV422; // m264 card only supports YUYV422 as input.
+ avctx->bits_per_raw_sample = 8;
+
+ if (avctx->extradata_size > 0 && avctx->extradata)
+ ret = m264_init_spspps_mp4(avctx);
+
+ return ret;
+}
+
+int ff_m264_receive_frame(AVCodecContext *avctx, AVFrame *frame)
+{
+ int ret = 0;
+ AVPacket pkt = {0};
+ void *buffer_context = NULL;
+ void *buffer = NULL;
+ unsigned long buffer_size = 0;
+ unsigned long line_size;
+ int line;
+ int actual_line_size;
+ unsigned char *srcmem,*dstmem;
+ long double duration = 0;
+
+ M264DecoderContext *m264_decoder_context = (M264DecoderContext *)avctx->priv_data;
+ ret = m264_decoder_context->receive_frame(m264_decoder_context->decoder_context, &buffer_context, &buffer, &buffer_size);
+ if (ret == -1) {
+ av_log(avctx, AV_LOG_DEBUG, "ff_m264_receive_frame: m264_decoder_context->receive_packet get eos, return AVERROR_EOF \n");
+ return AVERROR_EOF;
+ }
+
+ if (buffer_size > 0) {
+ if ((ret = ff_get_buffer(avctx, frame, 0)) < 0)
+ return ret;
+
+ line_size = buffer_size / avctx->height;
+ srcmem = (unsigned char *)buffer;
+ dstmem = (unsigned char *)frame->data[0];
+ actual_line_size = avctx->width * 2;
+
+ for (line = 0; line < avctx->height; line++) {
+ memcpy(dstmem, srcmem, actual_line_size);
+ dstmem += frame->linesize[0];
+ srcmem += line_size;
+ }
+
+ frame->pts = m264_decoder_context->frames * frame->pkt_duration;
+ m264_decoder_context->frames++;
+ av_log(avctx, AV_LOG_DEBUG, "ff_m264_receive_frame: m264_decoder_context->frames = %d\n", (int)m264_decoder_context->frames);
+ ret = m264_decoder_context->release_frame_buffer(m264_decoder_context->decoder_context, buffer_context);
+ } else {
+ if (m264_decoder_context->eof != 1) {
+ ret = ff_decode_get_packet(avctx, &pkt);
+ av_log(avctx, AV_LOG_DEBUG, "decoder: ff_m264_receive_frame: ff_decode_get_packet pkt.size = %d\n", pkt.size);
+ if (ret < 0 && ret != AVERROR_EOF)
+ return ret;
+ }
+
+ if (ret == AVERROR_EOF ) {
+ if (m264_decoder_context->eof != 1) {
+ pkt.data = NULL;
+ pkt.size = 0;
+ m264_decoder_context->eof = 1;
+ ret = m264_decoder_context->send_packet(m264_decoder_context->decoder_context, m264_decoder_context->sps_pps, m264_decoder_context->length_sps_pps, pkt.data, pkt.size, 0);
+ }
+ } else {
+ if (m264_decoder_context->eof != 1) {
+ av_log(avctx, AV_LOG_DEBUG, "decoder: ff_m264_receive_frame: pkt.side_data_elems = %d\n", pkt.side_data_elems);
+
+ if (pkt.data != NULL)
+ {
+ ret = m264_mp4_to_annexb(avctx, &pkt);
+ if (ret < 0)
+ return ret;
+ }
+
+ duration = (long double)pkt.duration * avctx->pkt_timebase.num / avctx->pkt_timebase.den;
+
+ if (pkt.flags)
+ ret = m264_decoder_context->send_packet(m264_decoder_context->decoder_context, m264_decoder_context->sps_pps, m264_decoder_context->length_sps_pps, pkt.data, pkt.size, duration);
+ else
+ ret = m264_decoder_context->send_packet(m264_decoder_context->decoder_context, NULL , 0, pkt.data, pkt.size, duration);
+ }
+ }
+ av_packet_unref(&pkt);
+ ret = AVERROR(EAGAIN);
+ }
+ return ret;
+}
+
+int av_cold ff_m264_decode_close(AVCodecContext *avctx)
+{
+ M264DecoderContext *m264_decoder_context = (M264DecoderContext *)avctx->priv_data;
+
+ if (m264_decoder_context) {
+
+ if (m264_decoder_context->decoder_context) {
+ m264_decoder_context->exit_m264_decoder(m264_decoder_context->decoder_context);
+ }
+
+ if (m264_decoder_context->lib_handle) {
+ dlclose(m264_decoder_context->lib_handle);
+ }
+
+ if (m264_decoder_context->ctx) {
+ av_bsf_free(&m264_decoder_context->ctx);
+ }
+
+ av_free(m264_decoder_context->sps_pps);
+ }
+
+ return 0;
+}
+
+#define OFFSET(x) offsetof(M264DecoderContext, x)
+#define VD AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_DECODING_PARAM
+static const AVOption h264_m264_decoder_options[] = {
+ { "resize", "Resize (width)x(height)", OFFSET(resize_expr), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, VD,"resize" },
+ { NULL }
+};
+
+static const AVClass h264_m264_decoder_class = {
+ .class_name = "h264_m264_decoder",
+ .item_name = av_default_item_name,
+ .option = h264_m264_decoder_options,
+ .version = LIBAVUTIL_VERSION_INT,
+};
+
+AVCodec ff_h264_m264_decoder = {
+ .name = "m264",
+ .long_name = NULL_IF_CONFIG_SMALL("Matrox M264 Codec"),
+ .type = AVMEDIA_TYPE_VIDEO,
+ .id = AV_CODEC_ID_H264,
+ .init = ff_m264_decode_init,
+ .receive_frame = ff_m264_receive_frame,
+ .close = ff_m264_decode_close,
+ .capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_HARDWARE,
+ .caps_internal = FF_CODEC_CAP_INIT_CLEANUP,
+ .priv_data_size = sizeof(M264DecoderContext),
+ .priv_class = &h264_m264_decoder_class,
+ .wrapper_name = "m264",
+};
new file mode 100644
@@ -0,0 +1,40 @@
+/*
+ * M264 H.264 video decoder
+ *
+ * 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
+ */
+
+/**
+ * @file
+ * Matrox M264 card supports h.264 encoding and decoding.
+ */
+
+#ifndef AVCODEC_M264DEC_H
+#define AVCODEC_M264DEC_H
+
+#include "libavutil/fifo.h"
+
+#include "avcodec.h"
+
+int ff_m264_decode_init(AVCodecContext *avctx);
+int ff_m264_decode_close(AVCodecContext *avctx);
+int ff_m264_receive_frame(AVCodecContext *avctx, AVFrame *frame);
+int m264_init_spspps_mp4(AVCodecContext *avctx);
+int m264_mp4_to_annexb(AVCodecContext *avctx, AVPacket *packet);
+
+#endif //AVCODEC_M264DEC_H
+
new file mode 100644
@@ -0,0 +1,335 @@
+/*
+ * M264 H.264 video encoder
+ *
+ * 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
+ */
+
+/**
+ * @file
+ * Matrox M264 card supports h.264 encoding and decoding.
+ */
+
+#include "libswscale/swscale.h"
+#include "m264enc.h"
+#include "internal.h"
+#include "profiles.h"
+#include "libavutil/opt.h"
+
+#ifdef _WIN32
+#include "compat/w32dlfcn.h"
+#else
+#include <dlfcn.h>
+#endif
+
+typedef struct {
+ uint16_t width;
+ uint16_t height;
+ uint16_t scale;
+ uint16_t rate;
+ uint16_t profile;
+ uint16_t level;
+ uint16_t gop_size;
+ uint32_t bitrate;
+} M264EncoderInfo;
+
+typedef struct {
+ AVClass *class;
+ int (*init_m264_encoder)(void *encoder_info, void **m264_encoder_object);
+ int (*exit_m264_encoder)(void *m264_encoder_object);
+ int (*get_extradata)(void *m264_encoder_object, void **extradata, unsigned long *extradata_size);
+ int (*get_uncompressed_buffer)(void *m264_encoder_object, void **buffer_context, void **buffer, unsigned long *buffer_size);
+ int (*send_frame)(void *m264_encoder_object, void *buffer_context, int polarity);
+ int (*receive_packet)(void *m264_encoder_object, void *buffer_context, void **buffer, unsigned long *buffer_size, int32_t *pts, int32_t *dts, int8_t *key);
+ int (*release_packet_buffer)(void *m264_encoder_object, void *buffer_context);
+ void *lib_handle;
+ void *encoder_context;
+ struct SwsContext *sw_context;
+ int profile;
+ int level;
+} M264EncoderContext;
+
+av_cold int ff_m264_encode_init(AVCodecContext *avctx)
+{
+ int ret = 0;
+ void *lib_handle;
+ M264EncoderContext *m264_encoder_context;
+ M264EncoderInfo encoder_info;
+ void *extradata = NULL;
+ unsigned long extradata_size = 0;
+
+ #ifdef _WIN32
+ lib_handle = dlopen("mvM264.dll", RTLD_LAZY);
+ #else
+ lib_handle = dlopen("libmvM264.so", RTLD_LAZY);
+ #endif
+
+ if (!lib_handle) {
+ av_log(avctx, AV_LOG_ERROR, "failed to load mvM264\n");
+ return AVERROR_ENCODER_NOT_FOUND;
+ }
+
+ m264_encoder_context = avctx->priv_data;
+
+ m264_encoder_context->init_m264_encoder = dlsym(lib_handle, "m264_encoder_init");
+ if (!m264_encoder_context->init_m264_encoder) {
+ av_log(avctx, AV_LOG_ERROR, "failed to load mvM264\n");
+ return AVERROR_ENCODER_NOT_FOUND;
+ }
+
+ m264_encoder_context->exit_m264_encoder = dlsym(lib_handle, "m264_encoder_exit");
+ if (!m264_encoder_context->exit_m264_encoder) {
+ av_log(avctx, AV_LOG_ERROR, "failed to load mvM264\n");
+ return AVERROR_ENCODER_NOT_FOUND;
+ }
+
+ m264_encoder_context->get_extradata = dlsym(lib_handle, "m264_encoder_get_extradata");
+ if (!m264_encoder_context->get_extradata) {
+ av_log(avctx, AV_LOG_ERROR, "failed to load mvM264\n");
+ return AVERROR_ENCODER_NOT_FOUND;
+ }
+
+ m264_encoder_context->get_uncompressed_buffer = dlsym(lib_handle, "m264_encoder_get_uncompressed_buffer");
+ if (!m264_encoder_context->get_uncompressed_buffer) {
+ av_log(avctx, AV_LOG_ERROR, "failed to load mvM264\n");
+ return AVERROR_ENCODER_NOT_FOUND;
+ }
+
+ m264_encoder_context->send_frame = dlsym(lib_handle, "m264_encoder_send_frame");
+ if (!m264_encoder_context->send_frame) {
+ av_log(avctx, AV_LOG_ERROR, "failed to load mvM264\n");
+ return AVERROR_ENCODER_NOT_FOUND;
+ }
+
+ m264_encoder_context->receive_packet = dlsym(lib_handle, "m264_encoder_receive_packet");
+ if (!m264_encoder_context->receive_packet) {
+ av_log(avctx, AV_LOG_ERROR, "failed to load mvM264\n");
+ return AVERROR_ENCODER_NOT_FOUND;
+ }
+
+ m264_encoder_context->release_packet_buffer = dlsym(lib_handle, "m264_encoder_release_packet_buffer");
+ if (!m264_encoder_context->release_packet_buffer) {
+ av_log(avctx, AV_LOG_ERROR, "failed to load mvM264\n");
+ return AVERROR_ENCODER_NOT_FOUND;
+ }
+
+ m264_encoder_context->lib_handle = lib_handle;
+
+ encoder_info.width = avctx->width;
+ encoder_info.height = avctx->height;
+ encoder_info.rate = avctx->framerate.num;
+ encoder_info.scale = avctx->framerate.den;
+ encoder_info.profile = m264_encoder_context->profile;
+ encoder_info.level = m264_encoder_context->level;
+ encoder_info.gop_size = avctx->gop_size;
+ encoder_info.bitrate = avctx->bit_rate;
+ av_log(avctx, AV_LOG_DEBUG, "m264_encode_init_h264: avctx->width = %d, avctx->height = %d, avctx->framerate.num = %d, avctx->framerate.den = %d, avctx->gop_size = %d, avctx->bit_rate = %" PRId64 "\n",
+ avctx->width, avctx->height, avctx->framerate.num, avctx->framerate.den, avctx->gop_size, avctx->bit_rate);
+
+ ret = m264_encoder_context->init_m264_encoder(&encoder_info, &(m264_encoder_context->encoder_context));
+ if (ret < 0)
+ return ret;
+
+ if (avctx->flags & AV_CODEC_FLAG_GLOBAL_HEADER) {
+ ret = m264_encoder_context->get_extradata(m264_encoder_context->encoder_context, &extradata, &extradata_size);
+ if (ret < 0)
+ return ret;
+
+ if (extradata_size > 0) {
+ avctx->extradata = av_mallocz(extradata_size + AV_INPUT_BUFFER_PADDING_SIZE);
+ if (!avctx->extradata)
+ return AVERROR(ENOMEM);
+ memcpy(avctx->extradata, extradata, extradata_size);
+ avctx->extradata_size = extradata_size;
+ }
+ }
+
+ return ret;
+}
+
+int ff_m264_send_frame(AVCodecContext *avctx, const AVFrame *frame)
+{
+ int ret = 0;
+ enum AVPixelFormat src_pixel_format;
+ enum AVPixelFormat dest_pixel_format;
+ uint8_t *dst[1];
+ int dst_stride[1];
+ void *buffer_context;
+ unsigned long buffer_size;
+ unsigned long line_size;
+ int line;
+ int actual_line_size;
+ unsigned char *srcmem,*dstmem;
+
+ M264EncoderContext *m264_encoder_context = (M264EncoderContext *)avctx->priv_data;
+
+ if (frame) {
+ src_pixel_format = (enum AVPixelFormat)frame->format;
+ dest_pixel_format = AV_PIX_FMT_YUYV422;
+ if (m264_encoder_context->sw_context == NULL) {
+ m264_encoder_context->sw_context = sws_getContext(frame->width, frame->height, src_pixel_format, frame->width, frame->height,
+ dest_pixel_format, SWS_BILINEAR, NULL, NULL, NULL);
+ if (!m264_encoder_context->sw_context) {
+ av_log(avctx, AV_LOG_ERROR, "failed to get sw_context\n");
+ ret = -1;
+ return ret;
+ }
+ }
+ ret = m264_encoder_context->get_uncompressed_buffer(m264_encoder_context->encoder_context, &buffer_context, (void **)&dst[0], &buffer_size);
+ if (ret < 0)
+ return ret;
+
+ dst_stride[0] = buffer_size / avctx->height;
+ if (src_pixel_format != AV_PIX_FMT_YUYV422) {
+ ret = sws_scale(m264_encoder_context->sw_context, (const uint8_t * const*)frame->data, frame->linesize, 0, frame->height, dst, dst_stride);
+ if (ret < 0)
+ return ret;
+ } else {
+ line_size = buffer_size / avctx->height;
+ dstmem = (unsigned char *)dst[0];
+ srcmem = (unsigned char *)frame->data[0];
+ actual_line_size = avctx->width * 2;
+
+ for (line = 0; line < avctx->height; line++) {
+ memcpy(dstmem, srcmem, actual_line_size);
+ srcmem += frame->linesize[0];
+ dstmem += line_size;
+ }
+ }
+ av_log(avctx, AV_LOG_DEBUG, "ff_m264_send_frame: frame->width = %d, frame->height = %d\n", frame->width, frame->height);
+ ret = m264_encoder_context->send_frame(m264_encoder_context->encoder_context, buffer_context, 0);
+ if (ret < 0)
+ return ret;
+ } else {
+ av_log(avctx, AV_LOG_DEBUG, "ff_m264_send_frame: frame is null. eof\n");
+ ret = m264_encoder_context->send_frame(m264_encoder_context->encoder_context, NULL, 0);
+ if (ret < 0)
+ return ret;
+ }
+ return ret;
+}
+
+int ff_m264_receive_packet(AVCodecContext *avctx, AVPacket *avpkt)
+{
+ int ret;
+ M264EncoderContext *m264_encoder_context = (M264EncoderContext *)avctx->priv_data;
+ void *buffer_context = NULL;
+ void *buffer = NULL;
+ unsigned long buffer_size = 0;
+ int32_t pts, dts;
+ int8_t key;
+
+ ret = m264_encoder_context->receive_packet(m264_encoder_context->encoder_context, &buffer_context, &buffer, &buffer_size, &pts, &dts, &key);
+ if (ret == -1) {
+ av_log(avctx, AV_LOG_DEBUG, "ff_m264_receive_packet: m264_encoder_context->receive_packet get eos, return AVERROR_EOF\n");
+ return AVERROR_EOF;
+ } else if (buffer_size == 0) {
+ return AVERROR(EAGAIN);
+ }
+
+ av_log(avctx, AV_LOG_DEBUG, "ff_m264_receive_packet m264_encoder_context->receive_packet buffer_size = %d\n", (int)buffer_size);
+
+ ret = ff_alloc_packet2(avctx, avpkt, buffer_size, 0);
+ if (ret < 0)
+ return ret;
+
+ memcpy(avpkt->data, buffer, buffer_size);
+
+ avpkt->dts = dts - 2;
+ avpkt->pts = pts;
+ avpkt->flags = key ? AV_PKT_FLAG_KEY : 0;
+ avpkt->duration = 1;
+
+ ret = m264_encoder_context->release_packet_buffer(m264_encoder_context->encoder_context, buffer_context);
+ if (ret < 0)
+ return ret;
+
+ return ret;
+}
+
+int av_cold ff_m264_encode_close(AVCodecContext *avctx)
+{
+ M264EncoderContext *m264_encoder_context = (M264EncoderContext *)avctx->priv_data;
+
+ if (m264_encoder_context) {
+ if (m264_encoder_context->encoder_context) {
+ m264_encoder_context->exit_m264_encoder(m264_encoder_context->encoder_context);
+ }
+
+ if (m264_encoder_context->sw_context) {
+ sws_freeContext(m264_encoder_context->sw_context);
+ }
+
+ if (m264_encoder_context->lib_handle) {
+ dlclose(m264_encoder_context->lib_handle);
+ }
+ }
+
+ return 0;
+}
+
+#define OFFSET(x) offsetof(M264EncoderContext, x)
+#define VE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM
+static const AVOption h264_m264_encoder_options[] = {
+ { "profile", "Set the encoding profile", OFFSET(profile), AV_OPT_TYPE_INT,{ .i64 = FF_PROFILE_H264_MAIN }, FF_PROFILE_H264_BASELINE, FF_PROFILE_H264_HIGH_444, VE, "profile" },
+ { "baseline", "", 0, AV_OPT_TYPE_CONST, { .i64 = FF_PROFILE_H264_BASELINE }, 0, 0, VE, "profile" },
+ { "main", "", 0, AV_OPT_TYPE_CONST, { .i64 = FF_PROFILE_H264_MAIN }, 0, 0, VE, "profile" },
+ { "high", "", 0, AV_OPT_TYPE_CONST, { .i64 = FF_PROFILE_H264_HIGH }, 0, 0, VE, "profile" },
+ { "high10", "", 0, AV_OPT_TYPE_CONST, { .i64 = FF_PROFILE_H264_HIGH_10 }, 0, 0, VE, "profile" },
+ { "high422", "", 0, AV_OPT_TYPE_CONST, { .i64 = FF_PROFILE_H264_HIGH_422 }, 0, 0, VE, "profile" },
+ { "level", "Profile Level", OFFSET(level), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 62, VE, "level" },
+ { "1.b", "", 0, AV_OPT_TYPE_CONST, { .i64 = 9 }, 0, 0, VE, "level" },
+ { "1", "", 0, AV_OPT_TYPE_CONST, { .i64 = 10 }, 0, 0, VE, "level" },
+ { "1.1", "", 0, AV_OPT_TYPE_CONST, { .i64 = 11 }, 0, 0, VE, "level" },
+ { "1.2", "", 0, AV_OPT_TYPE_CONST, { .i64 = 12 }, 0, 0, VE, "level" },
+ { "1.3", "", 0, AV_OPT_TYPE_CONST, { .i64 = 13 }, 0, 0, VE, "level" },
+ { "2.0", "", 0, AV_OPT_TYPE_CONST, { .i64 = 20 }, 0, 0, VE, "level" },
+ { "2.1", "", 0, AV_OPT_TYPE_CONST, { .i64 = 21 }, 0, 0, VE, "level" },
+ { "2.2", "", 0, AV_OPT_TYPE_CONST, { .i64 = 22 }, 0, 0, VE, "level" },
+ { "3.0", "", 0, AV_OPT_TYPE_CONST, { .i64 = 30 }, 0, 0, VE, "level" },
+ { "3.1", "", 0, AV_OPT_TYPE_CONST, { .i64 = 31 }, 0, 0, VE, "level" },
+ { "3.2", "", 0, AV_OPT_TYPE_CONST, { .i64 = 32 }, 0, 0, VE, "level" },
+ { "4.0", "", 0, AV_OPT_TYPE_CONST, { .i64 = 40 }, 0, 0, VE, "level" },
+ { "4.1", "", 0, AV_OPT_TYPE_CONST, { .i64 = 41 }, 0, 0, VE, "level" },
+ { "4.2", "", 0, AV_OPT_TYPE_CONST, { .i64 = 42 }, 0, 0, VE, "level" },
+ { "5.0", "", 0, AV_OPT_TYPE_CONST, { .i64 = 50 }, 0, 0, VE, "level" },
+ { "5.1", "", 0, AV_OPT_TYPE_CONST, { .i64 = 51 }, 0, 0, VE, "level" },
+ { "5.2", "", 0, AV_OPT_TYPE_CONST, { .i64 = 52 }, 0, 0, VE, "level" },
+ { NULL },
+};
+
+static const AVClass h264_m264_encoder_class = {
+ .class_name = "h264_m264_encoder",
+ .item_name = av_default_item_name,
+ .option = h264_m264_encoder_options,
+ .version = LIBAVUTIL_VERSION_INT,
+};
+
+AVCodec ff_h264_m264_encoder = {
+ .name = "m264",
+ .long_name = NULL_IF_CONFIG_SMALL("Matrox M264 Codec"),
+ .type = AVMEDIA_TYPE_VIDEO,
+ .id = AV_CODEC_ID_H264,
+ .init = ff_m264_encode_init,
+ .send_frame = ff_m264_send_frame,
+ .receive_packet = ff_m264_receive_packet,
+ .close = ff_m264_encode_close,
+ .capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_HARDWARE,
+ .caps_internal = FF_CODEC_CAP_INIT_CLEANUP,
+ .priv_data_size = sizeof(M264EncoderContext),
+ .priv_class = &h264_m264_encoder_class,
+ .wrapper_name = "m264",
+};
new file mode 100644
@@ -0,0 +1,38 @@
+/*
+ * M264 H.264 video encoder
+ *
+ * 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
+ */
+
+/**
+ * @file
+ * Matrox M264 card supports h.264 encoding and decoding.
+ */
+
+#ifndef AVCODEC_M264ENC_H
+#define AVCODEC_M264ENC_H
+
+#include "libavutil/fifo.h"
+
+#include "avcodec.h"
+
+int ff_m264_encode_init(AVCodecContext *avctx);
+int ff_m264_encode_close(AVCodecContext *avctx);
+int ff_m264_send_frame(AVCodecContext *avctx, const AVFrame *frame);
+int ff_m264_receive_packet(AVCodecContext *avctx, AVPacket *avpkt);
+
+#endif //AVCODEC_AMAVCODEC_M264ENC_H
--
2.7.4