diff --git a/configure b/configure
index b876e66..eca21e3 100755
--- a/configure
+++ b/configure
@@ -176,6 +176,7 @@ External library support:
   --enable-libvorbis       enable Vorbis encoding via libvorbis,
                            native implementation exists [no]
   --enable-libx264         enable H.264 encoding via x264 [no]
+  --enable-libcrusher264   enable H.264 encoding via crusher264 [no]"
   --enable-libxvid         enable Xvid encoding via xvidcore,
                            native MPEG-4/Xvid encoder exists [no]
   --enable-mlib            enable Sun medialib [no]
@@ -854,6 +855,7 @@ CONFIG_LIST="
     libtheora
     libvorbis
     libx264
+    libcrusher264
     libxvid
     lpc
     mdct
@@ -1201,6 +1203,7 @@ libspeex_decoder_deps="libspeex"
 libtheora_encoder_deps="libtheora"
 libvorbis_encoder_deps="libvorbis"
 libx264_encoder_deps="libx264"
+libcrusher264_encoder_deps="libcrusher264"
 libxvid_encoder_deps="libxvid"
 
 # demuxers / muxers
@@ -2083,6 +2086,7 @@ die_license_disabled() {
 
 die_license_disabled gpl libfaad2
 die_license_disabled gpl libx264
+die_license_disabled gpl libcrusher264
 die_license_disabled gpl libxvid
 die_license_disabled gpl postproc
 die_license_disabled gpl x11grab
@@ -2341,6 +2345,8 @@ enabled libvorbis  && require  libvorbis vorbis/vorbisenc.h vorbis_info_init -lv
 enabled libx264    && require  libx264 x264.h x264_encoder_encode -lx264 -lm &&
                       { check_cpp_condition x264.h "X264_BUILD >= 78" ||
                         die "ERROR: libx264 version must be >= 0.78."; }
+enabled libcrusher264    && add_cflags $(pkg-config --cflags crusher264) &&
+                      require  libcrusher264 crusher264/crusher.h crusher_encode $(pkg-config --libs crusher264)
 enabled libxvid    && require  libxvid xvid.h xvid_global -lxvidcore
 enabled mlib       && require  mediaLib mlib_types.h mlib_VectorSub_S16_U8_Mod -lmlib
 
@@ -2626,6 +2632,7 @@ echo "libspeex enabled          ${libspeex-no}"
 echo "libtheora enabled         ${libtheora-no}"
 echo "libvorbis enabled         ${libvorbis-no}"
 echo "libx264 enabled           ${libx264-no}"
+echo "libcrusher264 enabled     ${libcrusher264-no}"
 echo "libxvid enabled           ${libxvid-no}"
 echo "zlib enabled              ${zlib-no}"
 echo "bzlib enabled             ${bzlib-no}"
diff --git a/libavcodec/Makefile b/libavcodec/Makefile
index 21cba37..2680297 100644
--- a/libavcodec/Makefile
+++ b/libavcodec/Makefile
@@ -493,6 +493,7 @@ OBJS-$(CONFIG_LIBSPEEX_DECODER)           += libspeexdec.o
 OBJS-$(CONFIG_LIBTHEORA_ENCODER)          += libtheoraenc.o
 OBJS-$(CONFIG_LIBVORBIS_ENCODER)          += libvorbis.o
 OBJS-$(CONFIG_LIBX264_ENCODER)            += libx264.o
+OBJS-$(CONFIG_LIBCRUSHER264_ENCODER)      += libcrusher264.o
 OBJS-$(CONFIG_LIBXVID_ENCODER)            += libxvidff.o libxvid_rc.o
 
 # parsers
diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c
index 482cbd6..c76ba9a 100644
--- a/libavcodec/allcodecs.c
+++ b/libavcodec/allcodecs.c
@@ -323,6 +323,7 @@ void avcodec_register_all(void)
     REGISTER_ENCODER (LIBTHEORA, libtheora);
     REGISTER_ENCODER (LIBVORBIS, libvorbis);
     REGISTER_ENCODER (LIBX264, libx264);
+    REGISTER_ENCODER (LIBCRUSHER264, libcrusher264);
     REGISTER_ENCODER (LIBXVID, libxvid);
 
     /* parsers */
diff --git a/libavcodec/libcrusher264.c b/libavcodec/libcrusher264.c
new file mode 100644
index 0000000..97f3d0c
--- /dev/null
+++ b/libavcodec/libcrusher264.c
@@ -0,0 +1,264 @@
+/*
+ * H.264 encoding using the crusher264 library
+ * Copyright (c) 2009 Sergiy Gur'yev ( piratfm gmail com )
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+* @file libavcodec/libcrusher264.c
+* H.264 encoder support via libcrusher264 library and hardware accelerator; more details about the Crusher
+* reference platform can be found at http://tipok.org.ua/node/13.
+*/
+
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+
+/* FFmpeg includes */
+#include "avcodec.h"
+
+/* libcrusher264 includes */
+#include <crusher264/crusher.h>
+#include <crusher264/imgConverter.h>
+
+typedef struct CrusherEncContext {
+    crusher_t       enc;
+    imgConverter_t  converter;
+    uint8_t        *sps_pps;         ///< sps/pps frame, received from device
+    int             sps_pps_size;
+    int             curr_block;     ///< current qbox (it contains 1 or 2 h264 nals)
+} CrusherEncContext;
+
+/* parse every qbox, received in codec flushed event */
+static int add_nals(AVCodecContext *ctx, uint8_t *out_buff, int in_bufsize)
+{
+    CrusherEncContext *c4 = ctx->priv_data;
+    crusher_qbox_t *qbox=NULL;
+    uint8_t *buf = out_buff;
+    int bufsize = in_bufsize;
+    int i;
+    int datalen;
+
+    if(!c4->enc.out_blocks)
+        return 0;
+
+    for(i=c4->curr_block; i < c4->enc.out_blocks; i++) {
+        datalen = 0;
+        if(c4->enc.out_format == OUT_FORMAT_QBOX) {
+            qbox=crusher_qbox_parse(&c4->enc, c4->enc.out_data[i].data, c4->enc.out_data[i].len);
+            if(qbox) {
+                switch (qbox->sample_flags) {
+                    case CRUSHER_TYPE_SPS_PPS:
+                        c4->sps_pps_size = qbox->size - QBOX_HDR_SIZE;
+                        c4->sps_pps = av_realloc(c4->sps_pps, c4->sps_pps_size);
+                        memcpy(c4->sps_pps, qbox->data, c4->sps_pps_size);
+                        break;
+                    case CRUSHER_TYPE_IDR:
+                        ctx->coded_frame->pict_type = FF_I_TYPE;
+                        ctx->coded_frame->key_frame = 1;
+                        /* hack: no extradata present, send sps/pps every keyframe */
+                        if (bufsize < qbox->size - QBOX_HDR_SIZE + c4->sps_pps_size) {
+                            av_log(ctx, AV_LOG_ERROR, "encoded frame too large\n");
+                            return -1;
+                        }
+                        memcpy(buf, c4->sps_pps, c4->sps_pps_size);
+                        memcpy(buf + c4->sps_pps_size, qbox->data , qbox->size - QBOX_HDR_SIZE);
+                        datalen = c4->sps_pps_size + qbox->size - QBOX_HDR_SIZE;
+                        break;
+                    case CRUSHER_TYPE_P:
+                    case CRUSHER_TYPE_EMPTY:
+                        ctx->coded_frame->pict_type = FF_P_TYPE;
+                        ctx->coded_frame->key_frame = 0;
+                        if (bufsize < qbox->size - QBOX_HDR_SIZE) {
+                            av_log(ctx, AV_LOG_ERROR, "encoded frame too large\n");
+                            return -1;
+                        }
+                        datalen = qbox->size - QBOX_HDR_SIZE;
+                        memcpy(buf, qbox->data, datalen);
+                        break;
+                    default:
+                        av_log(ctx, AV_LOG_ERROR, "Unknown sample flags 0x%08x\n", qbox->sample_flags);
+                        return -1;
+                        break;
+                }
+            } else {
+                return 0;
+            }
+        } else {
+            /* this is for raw es stream format
+             * TODO: need sps/pps in extradata */
+            memcpy(buf, c4->enc.out_data[i].data, c4->enc.out_data[i].len);
+            datalen = c4->enc.out_data[i].len;
+        }
+        buf+=datalen;
+        bufsize-=datalen;
+    }
+    return in_bufsize - bufsize;
+}
+
+static int CrusherEnc_frame(AVCodecContext *ctx, uint8_t *buf,
+                                int bufsize, void *data)
+{
+    CrusherEncContext *c4 = ctx->priv_data;
+    AVFrame *frame = data;
+    int ret = -1;
+    int datalen = 0;
+
+    assert(ctx->pix_fmt == PIX_FMT_YUV420P);
+
+    if(frame){
+        /* Convert planes to the crusher format (UV12 blocked) */
+        if (frame->linesize[1] != frame->linesize[2]) {
+            av_log(ctx, AV_LOG_ERROR, "U and V stride differ\n");
+            return -1;
+        }
+
+        c4->converter.y_stride  = frame->linesize[0];
+        c4->converter.uv_stride = frame->linesize[1];
+        c4->converter.y = frame->data[0];
+        c4->converter.u = frame->data[1];
+        c4->converter.v = frame->data[2];
+        if (imgConverter_convert(&c4->converter) != CONVERTER_FINISHED) {
+            av_log(ctx, AV_LOG_ERROR, "Converter failed!\n");
+            return -1;
+        }
+
+        do  {
+            ret = crusher_encode(&c4->enc, c4->converter.iyuv_blocked, c4->converter.iyuv_frame_size_d);
+            if(ret == CODEC_FLUSHED) {
+                datalen+= add_nals(ctx, buf+datalen, bufsize-datalen);
+                /* hack: maybe qbox cts can be usable here? */
+                ctx->coded_frame->pts = frame->pts;
+            }
+        } while (ret == CODEC_FLUSHED);
+    } else if(!c4->enc.finished) {
+        av_log(ctx, AV_LOG_ERROR, "Codec finishing!\n");
+        do {
+            ret = crusher_encode(&c4->enc, NULL, 0);
+            if (ret == CODEC_FLUSHED)
+                datalen+=add_nals(ctx, buf + datalen, bufsize-datalen);
+        } while(ret != CODEC_FAIL && ret != CODEC_FINISHED);
+    }
+
+    if(ret == CODEC_FAIL) {
+        av_log(ctx, AV_LOG_ERROR, "Failed\n");
+        return -1;
+    }
+
+    return datalen;
+}
+
+static av_cold int CrusherEnc_close(AVCodecContext *avctx)
+{
+    CrusherEncContext *c4 = avctx->priv_data;
+
+    av_log(avctx, AV_LOG_ERROR, "Closing encoder\n");
+
+    imgConverter_free(&c4->converter);
+    crusher_close(&c4->enc);
+
+    av_freep(&avctx->coded_frame);
+    return 0;
+}
+
+static av_cold int CrusherEnc_init(AVCodecContext *avctx)
+{
+    CrusherEncContext *c4 = avctx->priv_data;
+
+    crusher_defaults(&c4->enc);
+    c4->enc.out_format = OUT_FORMAT_QBOX;
+    c4->enc.width      = avctx->width;
+    c4->enc.height     = avctx->height;
+    c4->enc.bitrate    = avctx->bit_rate;
+    c4->enc.framerate  = avctx->time_base.den;
+    c4->enc.gopsize    = avctx->gop_size;
+    if(avctx->rc_buffer_size)
+        c4->enc.rc_size = avctx->rc_buffer_size;
+
+    c4->enc.scenecut_threshold = avctx->scenechange_threshold;
+    c4->enc.deblock = (avctx->flags & CODEC_FLAG_LOOP_FILTER) ? 1 : 0;
+    c4->enc.deblock_alpha = avctx->deblockalpha;
+    c4->enc.deblock_beta = avctx->deblockbeta;
+
+    av_log(avctx, AV_LOG_ERROR, "fmt=%d, w=%d, h=%d, br=%d, fr=%d, gop_s=%d, rc_s=%d, sc_newgop=%d, db=%d, db_a=%d, db_b=%d",
+        c4->enc.out_format, c4->enc.width, c4->enc.height, c4->enc.bitrate, c4->enc.framerate, c4->enc.gopsize,
+        c4->enc.rc_size, c4->enc.scenecut_threshold, c4->enc.deblock, c4->enc.deblock_alpha, c4->enc.deblock_beta );
+
+    /* upload fx2 firmware if not done yet. */
+    if( !crusher_find_device(&c4->enc, 1) ) {
+        av_log(avctx, AV_LOG_ERROR, "device not found");
+        crusher_close(&c4->enc);
+        return -1;
+    }
+
+    if( !crusher_init_device(&c4->enc) ) {
+        av_log(avctx, AV_LOG_ERROR, "init faliled");
+        crusher_close(&c4->enc);
+        return -1;
+    }
+
+    /* send default textconfig. */
+    if( !crusher_send_textconfig(&c4->enc) ) {
+        av_log(avctx, AV_LOG_ERROR, "sending textconfig failed");
+        crusher_close(&c4->enc);
+    }
+
+    c4->converter.y_width   = avctx->width;
+    c4->converter.y_height  = avctx->height;
+    c4->converter.uv_width  = avctx->width / 2;
+    c4->converter.uv_height = avctx->height / 2;
+
+    imgConverter_init(&c4->converter);
+
+    /* need to know input frame length to allocate inner buffer */
+    c4->enc.inputFrameLen = c4->converter.iyuv_frame_size_d;
+    /* Set up the output AVFrame */
+    avctx->coded_frame= avcodec_alloc_frame();
+    c4->sps_pps = av_malloc(40);
+    c4->curr_block = 0;
+
+    if (avctx->flags & CODEC_FLAG_GLOBAL_HEADER) {
+        av_log(avctx, AV_LOG_ERROR, "extradata received only while encoding, no global header support yet");
+        imgConverter_free(&c4->converter);
+        crusher_close(&c4->enc);
+        return -1;
+    }
+
+    if(!crusher_start(&c4->enc)){
+        av_log(avctx, AV_LOG_ERROR, "starting codec device failed");
+        imgConverter_free(&c4->converter);
+        crusher_close(&c4->enc);
+        return -1;
+    }
+    return 0;
+}
+
+AVCodec libcrusher264_encoder = {
+    .name           = "libcrusher264",
+    .type           = CODEC_TYPE_VIDEO,
+    .id             = CODEC_ID_H264,
+    .priv_data_size = sizeof(CrusherEncContext),
+    .init           = CrusherEnc_init,
+    .encode         = CrusherEnc_frame,
+    .close          = CrusherEnc_close,
+    .capabilities   = CODEC_CAP_DELAY,
+    .pix_fmts       = (const enum PixelFormat[]) { PIX_FMT_YUV420P, PIX_FMT_NONE },
+    .long_name      = NULL_IF_CONFIG_SMALL("libcrusher264 H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10 (Hardwared)"),
+};
