From b1f7779028378f3e0d5360766a8591d0cf5a0a71 Mon Sep 17 00:00:00 2001
From: yhe <yhe@matrox.com>
Date: Thu, 14 Mar 2019 10:10:46 -0400
Subject: [PATCH] H.264 encoder and decoder support with Matrox M264.

---
 Changelog               |   1 +
 configure               |   2 +
 libavcodec/Makefile     |   2 +
 libavcodec/allcodecs.c  |   2 +
 libavcodec/codec_desc.c |   1 -
 libavcodec/m264dec.c    | 315 ++++++++++++++++++++++++++++++++++++++++++++++++
 libavcodec/m264dec.h    |  39 ++++++
 libavcodec/m264enc.c    | 296 +++++++++++++++++++++++++++++++++++++++++++++
 libavcodec/m264enc.h    |  38 ++++++
 9 files changed, 695 insertions(+), 1 deletion(-)
 create mode 100644 libavcodec/m264dec.c
 create mode 100644 libavcodec/m264dec.h
 create mode 100644 libavcodec/m264enc.c
 create mode 100644 libavcodec/m264enc.h

diff --git a/Changelog b/Changelog
index 4d80e5b..ce0daf8 100644
--- a/Changelog
+++ b/Changelog
@@ -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:
diff --git a/configure b/configure
index dcead3a..5a5d7d5 100755
--- a/configure
+++ b/configure
@@ -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"
 hap_decoder_select="snappy texturedsp"
 hap_encoder_deps="libsnappy"
 hap_encoder_select="texturedspenc"
diff --git a/libavcodec/Makefile b/libavcodec/Makefile
index 15c43a8..8e8f9ab 100644
--- a/libavcodec/Makefile
+++ b/libavcodec/Makefile
@@ -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
diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c
index b26aeca..c03a5a3 100644
--- a/libavcodec/allcodecs.c
+++ b/libavcodec/allcodecs.c
@@ -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;
diff --git a/libavcodec/codec_desc.c b/libavcodec/codec_desc.c
index a3de8e1..55c02a8 100644
--- a/libavcodec/codec_desc.c
+++ b/libavcodec/codec_desc.c
@@ -1705,7 +1705,6 @@ static const AVCodecDescriptor codec_descriptors[] = {
         .long_name = NULL_IF_CONFIG_SMALL("Gryphon's Anim Compressor"),
         .props     = AV_CODEC_PROP_LOSSY,
     },
-
     /* various PCM "codecs" */
     {
         .id        = AV_CODEC_ID_PCM_S16LE,
diff --git a/libavcodec/m264dec.c b/libavcodec/m264dec.c
new file mode 100644
index 0000000..f16716e
--- /dev/null
+++ b/libavcodec/m264dec.c
@@ -0,0 +1,315 @@
+/*
+ * 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 "m264dec.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 gop_size;
+   uint32_t bitrate;
+   uint8_t  field_order;
+} M264DecoderInfo;
+
+typedef struct {
+    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);
+    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;
+    AVBSFContext *ctx;
+} M264Decoder;
+
+int m264_mp4_to_annexb(AVCodecContext *avctx, AVPacket *packet)
+{
+    M264Decoder *m264_decoder = (M264Decoder *)avctx->priv_data;
+    int ret = 0;
+
+    if (m264_decoder->ctx)
+    {
+        ret = av_bsf_send_packet(m264_decoder->ctx, packet);
+        if (ret < 0)
+            return ret;
+
+        ret = av_bsf_receive_packet(m264_decoder->ctx, packet);
+        if (ret < 0)
+            return ret;
+    }
+
+    return ret;
+}
+
+int m264_init_spspps_mp4(AVCodecContext *avctx)
+{
+    M264Decoder *m264_decoder = (M264Decoder *)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->ctx = ctx;
+
+    return ret;
+}
+
+av_cold int ff_m264_decode_init(AVCodecContext *avctx)
+{
+    int ret = 0;
+    void *lib_handle;
+    M264Decoder *m264_decoder;
+    M264DecoderInfo decoder_info;
+
+    m264_decoder = av_mallocz(sizeof(M264Decoder));
+    if (!m264_decoder) 
+        return AVERROR(ENOMEM);
+
+    avctx->priv_data = m264_decoder;
+
+    #ifdef _WIN32
+    lib_handle = dlopen("mvM264Ffmpeg.dll", RTLD_LAZY);
+    #else   
+    lib_handle = dlopen("libmvM264Ffmpeg.so", RTLD_LAZY);
+    #endif
+
+    if (!lib_handle) {
+        av_log(avctx, AV_LOG_ERROR, "failed to load mvM264ffmpeg\n");
+        return AVERROR_DECODER_NOT_FOUND;
+    }
+
+    m264_decoder->lib_handle = lib_handle;
+
+    m264_decoder->init_m264_decoder = dlsym(lib_handle, "m264_ffmpeg_decoder_init");
+    if (!m264_decoder->init_m264_decoder) {
+        av_log(avctx, AV_LOG_ERROR, "failed to load mvM264ffmpeg\n");
+        return AVERROR_DECODER_NOT_FOUND;
+    }
+
+    m264_decoder->exit_m264_decoder = dlsym(lib_handle, "m264_ffmpeg_decoder_exit");
+    if (!m264_decoder->exit_m264_decoder) {
+        av_log(avctx, AV_LOG_ERROR, "failed to load mvM264ffmpeg\n");
+        return AVERROR_DECODER_NOT_FOUND;
+    }
+
+    m264_decoder->send_packet = dlsym(lib_handle, "m264_ffmpeg_decoder_send_packet");
+    if (!m264_decoder->send_packet) {
+        av_log(avctx, AV_LOG_ERROR, "failed to load mvM264ffmpeg\n");
+        return AVERROR_DECODER_NOT_FOUND;
+    }
+
+    m264_decoder->receive_frame = dlsym(lib_handle, "m264_ffmpeg_decoder_receive_frame");
+    if (!m264_decoder->receive_frame) {
+        av_log(avctx, AV_LOG_ERROR, "failed to load mvM264ffmpeg\n");
+        return AVERROR_DECODER_NOT_FOUND;
+    }
+
+    m264_decoder->release_frame_buffer = dlsym(lib_handle, "m264_ffmpeg_decoder_release_frame_buffer");
+    if (!m264_decoder->release_frame_buffer) {
+        av_log(avctx, AV_LOG_ERROR, "failed to load mvM264ffmpeg\n");
+        return AVERROR_DECODER_NOT_FOUND;
+    }
+
+    m264_decoder->eof = 0;
+
+    decoder_info.width = avctx->width;
+    decoder_info.height = avctx->height;
+    decoder_info.scale = avctx->framerate.num;
+    decoder_info.rate = avctx->framerate.den;
+    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->init_m264_decoder(&decoder_info, &(m264_decoder->decoder_context));
+    if (ret < 0)
+        return ret;
+
+    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;
+
+    M264Decoder *m264_decoder = (M264Decoder *)avctx->priv_data;
+    ret = m264_decoder->receive_frame(m264_decoder->decoder_context, &buffer_context, &buffer, &buffer_size);
+    if (ret == -1) {
+        av_log(avctx, AV_LOG_DEBUG, "ff_m264_receive_frame: m264_decoder->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->frames;
+        m264_decoder->frames++;
+        av_log(avctx, AV_LOG_DEBUG, "ff_m264_receive_frame: m264_decoder->frames = %d\n", (int)m264_decoder->frames);
+        ret = m264_decoder->release_frame_buffer(m264_decoder->decoder_context, buffer_context);
+    }
+    else
+    {
+        if (m264_decoder->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->eof != 1) {
+                pkt.data = NULL;
+                pkt.size = 0;
+                m264_decoder->eof = 1;
+                ret = m264_decoder->send_packet(m264_decoder->decoder_context, NULL, 0, pkt.data, pkt.size);
+            }
+        }
+        else 
+        {
+            if (m264_decoder->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;
+                }
+
+                if (pkt.flags)
+                    ret = m264_decoder->send_packet(m264_decoder->decoder_context, m264_decoder->ctx->par_out->extradata, m264_decoder->ctx->par_out->extradata_size, pkt.data, pkt.size);
+                else
+                    ret = m264_decoder->send_packet(m264_decoder->decoder_context, NULL , 0, pkt.data, pkt.size);
+            }
+        }
+        av_packet_unref(&pkt);
+        ret = AVERROR(EAGAIN);
+    }
+    return ret;
+}
+
+int av_cold ff_m264_decode_close(AVCodecContext *avctx)
+{
+    M264Decoder *m264_decoder = (M264Decoder *)avctx->priv_data;
+
+    if (m264_decoder)
+    {
+        if (m264_decoder->exit_m264_decoder)
+            m264_decoder->exit_m264_decoder(m264_decoder->decoder_context);
+            
+        if (m264_decoder->lib_handle)
+            dlclose(m264_decoder->lib_handle);   
+
+        if (m264_decoder->ctx)
+        {
+            av_bsf_free(&m264_decoder->ctx);
+        }
+
+        av_free(m264_decoder);
+        avctx->priv_data = NULL;
+    }
+
+    return 0;
+}
+
+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,
+    .wrapper_name   = "m264",
+};
diff --git a/libavcodec/m264dec.h b/libavcodec/m264dec.h
new file mode 100644
index 0000000..abcedb0
--- /dev/null
+++ b/libavcodec/m264dec.h
@@ -0,0 +1,39 @@
+/*
+ * 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
diff --git a/libavcodec/m264enc.c b/libavcodec/m264enc.c
new file mode 100644
index 0000000..14cd570
--- /dev/null
+++ b/libavcodec/m264enc.c
@@ -0,0 +1,296 @@
+/*
+ * 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"
+
+#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 gop_size;
+    uint32_t bitrate;
+} M264EncoderInfo;
+
+typedef struct {
+    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;
+} M264Encoder;
+
+av_cold int ff_m264_encode_init(AVCodecContext *avctx)
+{
+    int ret = 0;
+    void *lib_handle;
+    M264Encoder *m264_encoder;
+    M264EncoderInfo encoder_info;
+    void *extradata = NULL;
+    unsigned long extradata_size = 0;
+
+    m264_encoder =  av_mallocz(sizeof(M264Encoder));
+    if (!m264_encoder) 
+        return AVERROR(ENOMEM);
+
+    avctx->priv_data = m264_encoder;
+
+    #ifdef _WIN32
+    lib_handle = dlopen("mvM264Ffmpeg.dll", RTLD_LAZY);
+    #else   
+    lib_handle = dlopen("libmvM264Ffmpeg.so", RTLD_LAZY);
+    #endif
+
+    if (!lib_handle) {
+        av_log(avctx, AV_LOG_ERROR, "failed to load mvM264ffmpeg\n");
+        return AVERROR_ENCODER_NOT_FOUND;
+    }
+
+    m264_encoder->lib_handle = lib_handle;
+
+    m264_encoder->init_m264_encoder = dlsym(lib_handle, "m264_ffmpeg_encoder_init");
+    if (!m264_encoder->init_m264_encoder) {
+        av_log(avctx, AV_LOG_ERROR, "failed to load mvM264ffmpeg\n");
+        return AVERROR_ENCODER_NOT_FOUND;
+    }
+
+    m264_encoder->exit_m264_encoder = dlsym(lib_handle, "m264_ffmpeg_encoder_exit");
+    if (!m264_encoder->exit_m264_encoder) {
+        av_log(avctx, AV_LOG_ERROR, "failed to load mvM264ffmpeg\n");
+        return AVERROR_ENCODER_NOT_FOUND;
+    }
+
+    m264_encoder->get_extradata = dlsym(lib_handle, "m264_ffmpeg_encoder_get_extradata");
+    if (!m264_encoder->get_extradata) {
+        av_log(avctx, AV_LOG_ERROR, "failed to load mvM264ffmpeg\n");
+        return AVERROR_ENCODER_NOT_FOUND;
+    }
+    
+    m264_encoder->get_uncompressed_buffer = dlsym(lib_handle, "m264_ffmpeg_encoder_get_uncompressed_buffer");
+    if (!m264_encoder->get_uncompressed_buffer) {
+        av_log(avctx, AV_LOG_ERROR, "failed to load mvM264ffmpeg\n");
+        return AVERROR_ENCODER_NOT_FOUND;
+    }
+
+    m264_encoder->send_frame = dlsym(lib_handle, "m264_ffmpeg_encoder_send_frame");
+    if (!m264_encoder->send_frame) {
+        av_log(avctx, AV_LOG_ERROR, "failed to load mvM264ffmpeg\n");
+        return AVERROR_ENCODER_NOT_FOUND;
+    }
+
+    m264_encoder->receive_packet = dlsym(lib_handle, "m264_ffmpeg_encoder_receive_packet");
+    if (!m264_encoder->receive_packet) {
+        av_log(avctx, AV_LOG_ERROR, "failed to load mvM264ffmpeg\n");
+        return AVERROR_ENCODER_NOT_FOUND;
+    }
+
+    m264_encoder->release_packet_buffer = dlsym(lib_handle, "m264_ffmpeg_encoder_release_packet_buffer");
+    if (!m264_encoder->release_packet_buffer) {
+        av_log(avctx, AV_LOG_ERROR, "failed to load mvM264ffmpeg\n");
+        return AVERROR_ENCODER_NOT_FOUND;
+    }
+
+    encoder_info.width = avctx->width;
+    encoder_info.height = avctx->height;
+    encoder_info.rate = avctx->framerate.num;
+    encoder_info.scale = avctx->framerate.den;
+    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->init_m264_encoder(&encoder_info, &(m264_encoder->encoder_context));
+    if (ret < 0)
+        return ret;
+
+    if (avctx->flags & AV_CODEC_FLAG_GLOBAL_HEADER) {
+        ret = m264_encoder->get_extradata(m264_encoder->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;
+
+    M264Encoder *m264_encoder = (M264Encoder *)avctx->priv_data;
+
+    if (frame) {
+        src_pixel_format = (enum AVPixelFormat)frame->format;
+        dest_pixel_format = AV_PIX_FMT_YUYV422;
+        if (m264_encoder->sw_context == NULL) {
+            m264_encoder->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->sw_context) {
+                av_log(avctx, AV_LOG_ERROR, "failed to load mvm264ffmpeg.so \n");
+                ret = -1;
+                return ret;
+            }
+        }
+        ret = m264_encoder->get_uncompressed_buffer(m264_encoder->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->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->send_frame(m264_encoder->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->send_frame(m264_encoder->encoder_context, NULL, 0);
+        if (ret < 0)
+            return ret;
+    }
+    return ret;
+}
+
+int ff_m264_receive_packet(AVCodecContext *avctx, AVPacket *avpkt)
+{
+    int ret;
+    M264Encoder *m264_encoder = (M264Encoder *)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->receive_packet(m264_encoder->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->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->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;
+    avpkt->pts = pts + 2;
+    avpkt->flags = key ? AV_PKT_FLAG_KEY : 0;
+
+    ret = m264_encoder->release_packet_buffer(m264_encoder->encoder_context, buffer_context);
+    if (ret < 0)
+        return ret;
+
+    return ret;
+}
+
+int av_cold ff_m264_encode_close(AVCodecContext *avctx)
+{
+    M264Encoder *m264_encoder = (M264Encoder *)avctx->priv_data;
+
+    if (m264_encoder)
+    {
+        if (m264_encoder->exit_m264_encoder)
+            m264_encoder->exit_m264_encoder(m264_encoder->encoder_context);
+
+        sws_freeContext(m264_encoder->sw_context);
+
+        if (m264_encoder->lib_handle)
+            dlclose(m264_encoder->lib_handle);   
+            
+        av_free(m264_encoder);
+        avctx->priv_data = NULL;
+    }
+    
+    return 0;
+}
+
+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,
+    .wrapper_name   = "m264",
+};
diff --git a/libavcodec/m264enc.h b/libavcodec/m264enc.h
new file mode 100644
index 0000000..0c44b32
--- /dev/null
+++ b/libavcodec/m264enc.h
@@ -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

