Forked from dhpollack/ffmpeg-0.6.1-libcrusher264-svn-r69.patch
Created
July 2, 2012 14:25
-
-
Save lynxis/3033513 to your computer and use it in GitHub Desktop.
Updated crusher264 patch for FFmpeg 0.6.1 (tested on Dockstar)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/configure b/configure | |
index d725942..6e95687 100755 | |
--- a/configure | |
+++ b/configure | |
@@ -166,6 +166,7 @@ External library support: | |
--enable-libopencore-amrnb enable AMR-NB de/encoding via libopencore-amrnb [no] | |
--enable-libopencore-amrwb enable AMR-WB decoding via libopencore-amrwb [no] | |
--enable-libopencv enable video filtering via libopencv [no] | |
+ --enable-libcrusher264 enable H.264 encoding via crusher264 [no] | |
--enable-libdc1394 enable IIDC-1394 grabbing using libdc1394 | |
and libraw1394 [no] | |
--enable-libdirac enable Dirac support via libdirac [no] | |
@@ -882,6 +883,7 @@ CONFIG_LIST=" | |
h264pred | |
hardcoded_tables | |
huffman | |
+ libcrusher264 | |
libdc1394 | |
libdirac | |
libfaac | |
@@ -1320,6 +1322,7 @@ vdpau_deps="vdpau_vdpau_h vdpau_vdpau_x11_h" | |
h264_parser_select="golomb h264dsp h264pred" | |
# external libraries | |
+libcrusher264_encoder_deps="libcrusher264 qbox_demuxer" | |
libdirac_decoder_deps="libdirac !libschroedinger" | |
libdirac_encoder_deps="libdirac" | |
libfaac_encoder_deps="libfaac" | |
@@ -1376,6 +1379,7 @@ w64_demuxer_deps="wav_demuxer" | |
alsa_indev_deps="alsa_asoundlib_h snd_pcm_htimestamp" | |
alsa_outdev_deps="alsa_asoundlib_h" | |
bktr_indev_deps_any="dev_bktr_ioctl_bt848_h machine_ioctl_bt848_h dev_video_bktr_ioctl_bt848_h dev_ic_bt8xx_h" | |
+crushercap_indev_deps="libcrusher264 crushercap qbox_demuxer" | |
dv1394_indev_deps="dv1394 dv_demuxer" | |
jack_indev_deps="jack_jack_h" | |
libdc1394_indev_deps="libdc1394" | |
@@ -2382,6 +2386,7 @@ case $target_os in | |
enable dos_paths | |
;; | |
linux) | |
+ enable crushercap | |
enable dv1394 | |
;; | |
irix*) | |
@@ -2445,6 +2450,7 @@ die_license_disabled() { | |
enabled $1 || { enabled $2 && die "$2 is $1 and --enable-$1 is not specified."; } | |
} | |
+die_license_disabled gpl libcrusher264 | |
die_license_disabled gpl libx264 | |
die_license_disabled gpl libxavs | |
die_license_disabled gpl libxvid | |
@@ -2741,6 +2747,8 @@ check_mathfunc roundf | |
check_mathfunc truncf | |
# these are off by default, so fail if requested and not available | |
+enabled libcrusher264 && add_cflags $(pkg-config --cflags crusher264) && | |
+ require libcrusher264 crusher264/crusher.h crusher_encode $(pkg-config --libs crusher264) | |
enabled avisynth && require2 vfw32 "windows.h vfw.h" AVIFileInit -lavifil32 | |
enabled frei0r && { check_header frei0r.h || die "ERROR: frei0r.h header not found"; } | |
enabled libdirac && add_cflags $(pkg-config --cflags dirac) && | |
@@ -3036,6 +3044,7 @@ echo "SDL support ${sdl-no}" | |
echo "Sun medialib support ${mlib-no}" | |
echo "AVISynth enabled ${avisynth-no}" | |
echo "frei0r enabled ${frei0r-no}" | |
+echo "libcrusher264 enabled ${libcrusher264-no}" | |
echo "libdc1394 support ${libdc1394-no}" | |
echo "libdirac enabled ${libdirac-no}" | |
echo "libfaac enabled ${libfaac-no}" | |
diff --git a/doc/general.texi b/doc/general.texi | |
index f59258c..6a080b3 100644 | |
--- a/doc/general.texi | |
+++ b/doc/general.texi | |
@@ -156,6 +156,8 @@ library: | |
@item Ogg @tab X @tab X | |
@item TechnoTrend PVA @tab @tab X | |
@tab Used by TechnoTrend DVB PCI boards. | |
+@item QBOX @tab @tab X | |
+ @tab Used by Maxim codec chips | |
@item QCP @tab @tab X | |
@item raw ADTS (AAC) @tab X @tab X | |
@item raw AC-3 @tab X @tab X | |
diff --git a/libavcodec/Makefile b/libavcodec/Makefile | |
index 385ae02..10b89e5 100644 | |
--- a/libavcodec/Makefile | |
+++ b/libavcodec/Makefile | |
@@ -530,6 +530,7 @@ OBJS-$(CONFIG_WEBM_MUXER) += xiph.o mpeg4audio.o \ | |
flacdec.o flacdata.o flac.o | |
# external codec libraries | |
+OBJS-$(CONFIG_LIBCRUSHER264_ENCODER) += libcrusher264.o | |
OBJS-$(CONFIG_LIBDIRAC_DECODER) += libdiracdec.o | |
OBJS-$(CONFIG_LIBDIRAC_ENCODER) += libdiracenc.o libdirac_libschro.o | |
OBJS-$(CONFIG_LIBFAAC_ENCODER) += libfaac.o | |
diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c | |
index 89614ab..6626c06 100644 | |
--- a/libavcodec/allcodecs.c | |
+++ b/libavcodec/allcodecs.c | |
@@ -347,6 +347,7 @@ void avcodec_register_all(void) | |
REGISTER_ENCDEC (XSUB, xsub); | |
/* external libraries */ | |
+ REGISTER_ENCODER (LIBCRUSHER264, libcrusher264); | |
REGISTER_ENCDEC (LIBDIRAC, libdirac); | |
REGISTER_ENCODER (LIBFAAC, libfaac); | |
REGISTER_ENCDEC (LIBGSM, libgsm); | |
diff --git a/libavcodec/libcrusher264.c b/libavcodec/libcrusher264.c | |
new file mode 100644 | |
index 0000000..ae39a87 | |
--- /dev/null | |
+++ b/libavcodec/libcrusher264.c | |
@@ -0,0 +1,466 @@ | |
+/* | |
+ * H.264 encoding using Maxim's hardware codec | |
+ * 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" | |
+#include "dsputil.h" | |
+#include "libavformat/qbox.h" | |
+ | |
+/* libcrusher264 includes */ | |
+#include <crusher264/crusher.h> | |
+ | |
+#undef CRUSHER_EXTRA_DEBUG | |
+ | |
+typedef struct CrusherEncContext { | |
+ crusher_t enc; | |
+ 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) | |
+ int frames_buff_size; | |
+ int frames_buff_fill; | |
+ int frames_buff_skip; | |
+ qboxContext *frames_buff; ///< output buffer | |
+ int frames_delay; | |
+ int conv_lines; | |
+ int conv_uv_lines; | |
+ AVPicture conv_input; | |
+ AVPicture conv_output; | |
+} CrusherEncContext; | |
+ | |
+ | |
+/** convert part of image with height=32 and width=64 | |
+ * 32 64 | |
+ *ptr_in->+--------+--------+ | |
+ * | 1 | 2 | | |
+ * 16 +--------+--------+ | |
+ * | 3 | 4 | | |
+ * 32 +--------+--------+ | |
+ */ | |
+static inline void conv_copy4_16x32(uint8_t *ptr_out, uint8_t *ptr_in, uint16_t Stride) | |
+{ | |
+ int line; | |
+ for (line=0; line < 16; line++) { | |
+ memcpy (ptr_out + (line*32), ptr_in + (line*Stride), 32); | |
+ memcpy (ptr_out + (line*32) + (32*16), ptr_in + (line*Stride) + 32, 32); | |
+ memcpy (ptr_out + (line*32) + (32*16)*2, ptr_in + (line*Stride) + (16*Stride), 32); | |
+ memcpy (ptr_out + (line*32) + (32*16)*3, ptr_in + (line*Stride) + (16*Stride) + 32, 32); | |
+ } | |
+} | |
+ | |
+/** convert 32 lines | |
+ */ | |
+static inline void conv_copy32Lines(uint8_t *ptr_out, uint8_t *ptr_in, uint8_t cols) | |
+{ | |
+ int fourBlockNum; | |
+ const uint16_t Stride = cols*(2*32); | |
+ for(fourBlockNum = 0; fourBlockNum < cols; fourBlockNum++) | |
+ conv_copy4_16x32(ptr_out + (32*16)*4*fourBlockNum, ptr_in + (32*2)*fourBlockNum, Stride); | |
+} | |
+ | |
+/** convert full frame | |
+ */ | |
+static void conv_frame(CrusherEncContext *ctx) | |
+{ | |
+ const int cols = ctx->conv_input.linesize[0] >> 6; | |
+ const int rows = (ctx->conv_lines + ctx->conv_uv_lines) >> 5; | |
+ | |
+ const int lines_32_size = (32*16) * 2 * 2 * cols; | |
+ int lines_32_num; | |
+ for(lines_32_num = 0; lines_32_num < rows; lines_32_num++) | |
+ conv_copy32Lines(ctx->conv_output.data[0] + lines_32_size * lines_32_num, | |
+ ctx->conv_input.data[0] + lines_32_size * lines_32_num, cols); | |
+} | |
+ | |
+/** parse every qbox, received from codec, when have "flush" event | |
+ */ | |
+static int add_nals(AVCodecContext *ctx, int alloc_buff) | |
+{ | |
+ CrusherEncContext *c4 = ctx->priv_data; | |
+ qboxContext qbox; | |
+ int i; | |
+ int oldptr = c4->frames_buff_fill; | |
+ | |
+ if(!c4->enc.out_blocks) | |
+ return 0; | |
+ | |
+ /* in most cases we have 6 qboxes at one event */ | |
+ for(i=c4->curr_block; i < c4->enc.out_blocks; i++) { | |
+ if(ff_qbox_parse(&qbox, c4->enc.out_data[i].data, c4->enc.out_data[i].len)) { | |
+#ifdef CRUSHER_EXTRA_DEBUG | |
+ av_log(ctx, AV_LOG_DEBUG, "QBOX: sst:0x%08x sf:0x%08x l:%d ts:%d\n", | |
+ qbox.sample_stream_type, qbox.sample_flags, qbox.qbox_size, qbox.sample_cts); | |
+#endif | |
+ if(qbox.sample_stream_type != SAMPLE_TYPE_H264) { | |
+ av_log(ctx, AV_LOG_ERROR, "Unknown sample flags 0x%08x (maybe audio?)\n", qbox.sample_flags); | |
+ return -1; | |
+ } | |
+ | |
+ if(!ff_qbox_make_startcode(qbox.data, qbox.qbox_size)){ | |
+ av_log(ctx, AV_LOG_ERROR, "can't create H264 startcodes\n"); | |
+ return -1; | |
+ } | |
+ | |
+ /* payload started ? */ | |
+ if(qbox.sample_flags & SAMPLE_FLAGS_CONFIGURATION_INFO) { | |
+ if(alloc_buff) { | |
+ c4->sps_pps_size = qbox.qbox_size; | |
+ c4->sps_pps = av_malloc(c4->sps_pps_size); | |
+ memcpy(c4->sps_pps, qbox.data, c4->sps_pps_size); | |
+ } else { | |
+ av_log(ctx, AV_LOG_ERROR, "SPS/PPS received in the middle of encoding\n"); | |
+ } | |
+ } else { | |
+ if(c4->frames_buff_skip) { | |
+ c4->frames_buff_skip--; | |
+ continue; | |
+ } | |
+ if(c4->frames_buff_fill == c4->frames_buff_size) { | |
+ if(alloc_buff) { | |
+ c4->frames_buff_size++; | |
+ c4->frames_buff = av_realloc(c4->frames_buff, sizeof(qboxContext) * c4->frames_buff_size); | |
+ } else { | |
+ av_log(ctx, AV_LOG_ERROR, "too small buffer (%d frames)\n", c4->frames_buff_size); | |
+ return -1; | |
+ } | |
+ } | |
+ | |
+ memcpy(&c4->frames_buff[c4->frames_buff_fill], &qbox, QBOX_HDR_SIZE); | |
+ /* add extradata if needed */ | |
+ if (ctx->flags & CODEC_FLAG_GLOBAL_HEADER || !(qbox.sample_flags & SAMPLE_FLAGS_SYNC_POINT)) { | |
+ c4->frames_buff[c4->frames_buff_fill].data = av_malloc(qbox.qbox_size); | |
+ memcpy(c4->frames_buff[c4->frames_buff_fill].data, qbox.data, qbox.qbox_size); | |
+ } else { /* sync point and no global header */ | |
+ c4->frames_buff[c4->frames_buff_fill].qbox_size+=c4->sps_pps_size; | |
+ c4->frames_buff[c4->frames_buff_fill].data = av_malloc(c4->frames_buff[c4->frames_buff_fill].qbox_size); | |
+ memcpy(c4->frames_buff[c4->frames_buff_fill].data, c4->sps_pps, c4->sps_pps_size); | |
+ memcpy(c4->frames_buff[c4->frames_buff_fill].data + c4->sps_pps_size, qbox.data, qbox.qbox_size); | |
+ } | |
+ | |
+ c4->frames_buff_fill++; | |
+ } | |
+ } | |
+ } | |
+ return c4->frames_buff_fill - oldptr; | |
+} | |
+ | |
+ | |
+/** encode dummy gop | |
+ * Huge workaround: | |
+ * Due sps/pps sent only while encoding started, force sending | |
+ * gop with empty frames until extradata received from device, | |
+ * also count frames, buffered inside device | |
+ */ | |
+static int encode_dummy_gops(AVCodecContext *ctx) | |
+{ | |
+ CrusherEncContext *c4 = ctx->priv_data; | |
+ int i, ret, frames2send = 0; | |
+ int sended_frames = 0; | |
+ | |
+ c4->frames_buff_size=0; | |
+ c4->frames_buff_fill=0; | |
+ c4->frames_buff = av_malloc(sizeof(qboxContext) * c4->frames_buff_size); | |
+ | |
+ do { | |
+ do { | |
+ ret = crusher_encode(&c4->enc, c4->conv_output.data[0], c4->enc.inputFrameLen); | |
+ if(ret == CODEC_FLUSHED) | |
+ add_nals(ctx, 1); | |
+ } while (ret == CODEC_FLUSHED); | |
+ sended_frames++; | |
+ } while (ret != CODEC_FAIL && ret != CODEC_FINISHED && !c4->sps_pps_size); | |
+ | |
+ if(ret == CODEC_FAIL || ret == CODEC_FINISHED || !c4->sps_pps_size) | |
+ return -1; | |
+ | |
+ if(sended_frames % c4->enc.gopsize) | |
+ frames2send = c4->enc.gopsize - (sended_frames % c4->enc.gopsize); | |
+ c4->frames_delay = sended_frames;// - c4->frames_buff_fill; | |
+#ifdef CRUSHER_EXTRA_DEBUG | |
+ av_log(ctx, AV_LOG_DEBUG, "sent: %d, need more %d frames to fill gop %d\n", | |
+ sended_frames, frames2send, c4->enc.gopsize); | |
+#endif | |
+ do { | |
+ do { | |
+ ret = crusher_encode(&c4->enc, c4->conv_output.data[0], c4->enc.inputFrameLen); | |
+ if(ret == CODEC_FLUSHED) | |
+ add_nals(ctx, 1); | |
+ } while (ret == CODEC_FLUSHED); | |
+ frames2send--; | |
+ sended_frames++; | |
+ } while (ret != CODEC_FAIL && ret != CODEC_FINISHED && frames2send); | |
+ | |
+ if(ret == CODEC_FAIL || ret == CODEC_FINISHED || sended_frames % c4->enc.gopsize) | |
+ return -1; | |
+ | |
+ c4->frames_buff_skip = sended_frames - c4->frames_buff_fill; | |
+#ifdef CRUSHER_EXTRA_DEBUG | |
+ av_log(ctx, AV_LOG_DEBUG, "skipping %d empy frames\n", c4->frames_buff_skip); | |
+#endif | |
+ | |
+ /* free allocated data for params detection */ | |
+ for (i=0; i < c4->frames_buff_fill; i++) | |
+ av_free(c4->frames_buff[i].data); | |
+ | |
+#ifdef CRUSHER_EXTRA_DEBUG | |
+ av_log(ctx, AV_LOG_DEBUG, "Codec buffer: size:%d, ptr:%d, sended:%d\n", | |
+ c4->frames_buff_size, c4->frames_buff_fill, sended_frames); | |
+#endif | |
+ | |
+ c4->frames_buff_size = c4->frames_delay; | |
+ c4->frames_buff_fill = 0; | |
+ c4->frames_buff = av_realloc(c4->frames_buff, sizeof(qboxContext) * c4->frames_buff_size); | |
+ | |
+#ifdef CRUSHER_EXTRA_DEBUG | |
+ av_log(ctx, AV_LOG_DEBUG, "new buff size: %d\n", c4->frames_buff_size); | |
+#endif | |
+ return sended_frames; | |
+} | |
+ | |
+/** encode 1 frame | |
+ */ | |
+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_NV12); | |
+ | |
+ if(frame) { | |
+ /* canvas size & copy frame | |
+ * can't use av_picture_copy due uv width must be equal y width */ | |
+ ff_img_copy_plane(c4->conv_input.data[0], c4->conv_input.linesize[0], | |
+ frame->data[0], frame->linesize[0], ctx->width, ctx->height); | |
+ ff_img_copy_plane(c4->conv_input.data[1], c4->conv_input.linesize[1], | |
+ frame->data[1], frame->linesize[1], ctx->width, ctx->height>>1); | |
+ | |
+ /* Convert planes to the crusher format (sequence of 32x16 blocks in NV12 format) */ | |
+ conv_frame(c4); | |
+ do { | |
+ ret = crusher_encode(&c4->enc, c4->conv_output.data[0], c4->enc.inputFrameLen); | |
+ if(ret == CODEC_FLUSHED) | |
+ add_nals(ctx, 0); | |
+ } while (ret == CODEC_FLUSHED); | |
+ } else if(!c4->enc.finished) { | |
+ av_log(ctx, AV_LOG_DEBUG, "Codec finishing!\n"); | |
+ do { | |
+ ret = crusher_encode(&c4->enc, NULL, 0); | |
+ if (ret == CODEC_FLUSHED) | |
+ add_nals(ctx, 0); | |
+ } while(ret != CODEC_FAIL && ret != CODEC_FINISHED); | |
+ } | |
+ | |
+ if(ret == CODEC_FAIL) { | |
+ av_log(ctx, AV_LOG_ERROR, "Failed\n"); | |
+ return -1; | |
+ } | |
+ | |
+ /* send frame from buffer */ | |
+ if(c4->frames_buff_fill) { | |
+ assert(bufsize >= c4->frames_buff[0].size); | |
+#ifdef CRUSHER_EXTRA_DEBUG | |
+ av_log(ctx, AV_LOG_DEBUG, "Frame out[0/%d/%d]:" | |
+ "len:%d, type:%d, ts:%d\n", | |
+ c4->frames_buff_fill, c4->frames_buff_size, | |
+ c4->frames_buff[0].qbox_size, | |
+ c4->frames_buff[0].sample_stream_type, | |
+ c4->frames_buff[0].sample_cts); | |
+#endif | |
+ datalen = c4->frames_buff[0].qbox_size; | |
+ memcpy(buf, c4->frames_buff[0].data, datalen); | |
+ av_freep(&c4->frames_buff[0].data); | |
+ | |
+ if(c4->frames_buff[0].sample_flags & SAMPLE_FLAGS_SYNC_POINT) { | |
+ ctx->coded_frame->key_frame = 1; | |
+ ctx->coded_frame->pict_type = FF_I_TYPE; | |
+ } else { | |
+ ctx->coded_frame->key_frame = 0; | |
+ ctx->coded_frame->pict_type = FF_P_TYPE; | |
+ } | |
+ //just return number of frame? | |
+ if (c4->frames_buff[0].sample_flags & SAMPLE_FLAGS_CTS_PRESENT) { | |
+ ctx->coded_frame->pts = c4->frames_buff[0].sample_cts/c4->enc.framerate_den - c4->frames_delay; | |
+ } else { | |
+ ctx->coded_frame->pts = AV_NOPTS_VALUE; | |
+ } | |
+ | |
+ c4->frames_buff_fill--; | |
+ if(c4->frames_buff_fill) | |
+ memmove(&c4->frames_buff[0], &c4->frames_buff[1], c4->frames_buff_fill * sizeof(qboxContext)); | |
+ } else if(frame) { | |
+ av_log(ctx, AV_LOG_DEBUG, "no frames in buffer\n"); | |
+ } else { | |
+ av_log(ctx, AV_LOG_DEBUG, "no more input and output frames\n"); | |
+ } | |
+ | |
+ return datalen; | |
+} | |
+ | |
+static av_cold int CrusherEnc_close(AVCodecContext *avctx) | |
+{ | |
+ CrusherEncContext *c4 = avctx->priv_data; | |
+ int i; | |
+ | |
+ av_log(avctx, AV_LOG_DEBUG, "Closing encoder\n"); | |
+ | |
+ avpicture_free(&c4->conv_input); | |
+ avpicture_free(&c4->conv_output); | |
+ crusher_close(&c4->enc); | |
+ | |
+ for (i=0; i < c4->frames_buff_fill; i++) | |
+ av_freep(&c4->frames_buff[i].data); | |
+ av_freep(&c4->frames_buff); | |
+ av_freep(&avctx->coded_frame); | |
+ return 0; | |
+} | |
+ | |
+static av_cold int CrusherEnc_init(AVCodecContext *avctx) | |
+{ | |
+ CrusherEncContext *c4 = avctx->priv_data; | |
+ | |
+ assert(ctx->avctx == PIX_FMT_NV12); | |
+ | |
+ crusher_defaults(&c4->enc); | |
+ /* upload fx2 firmware if not done yet. */ | |
+ if( !crusher_find_device(&c4->enc, 1) ) { | |
+ av_log(avctx, AV_LOG_ERROR, "device not found"); | |
+ goto CrusherEnc_init_fail; | |
+ } | |
+ | |
+ 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_den = avctx->time_base.num; | |
+ c4->enc.framerate_num = 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; | |
+#ifdef CRUSHER_EXTRA_DEBUG | |
+ av_log(avctx, AV_LOG_DEBUG, "fmt=%d, w=%d, h=%d, br=%d, gop_s=%d, rc_s=%d, sc_newgop=%d, db=%d, db_a=%d, db_b=%d\ntb: num=%d, den=%d\n", | |
+ c4->enc.out_format, c4->enc.width, c4->enc.height, c4->enc.bitrate, c4->enc.gopsize, | |
+ c4->enc.rc_size, c4->enc.scenecut_threshold, c4->enc.deblock, c4->enc.deblock_alpha, c4->enc.deblock_beta, avctx->time_base.num, avctx->time_base.den); | |
+#endif | |
+ | |
+ if( !crusher_init_device(&c4->enc) ) { | |
+ av_log(avctx, AV_LOG_ERROR, "init failed"); | |
+ goto CrusherEnc_init_fail; | |
+ } | |
+ | |
+ /* send default textconfig. */ | |
+ if( !crusher_send_textconfig(&c4->enc) ) { | |
+ av_log(avctx, AV_LOG_ERROR, "sending textconfig failed"); | |
+ goto CrusherEnc_init_fail; | |
+ } | |
+ | |
+ c4->conv_input.linesize[0] = FFALIGN(avctx->width, 64); | |
+ c4->conv_lines = FFALIGN(avctx->height, 32); | |
+ c4->conv_uv_lines = FFALIGN(RSHIFT(avctx->height, 1), 32); | |
+ c4->enc.inputFrameLen = c4->conv_input.linesize[0] * (c4->conv_lines + c4->conv_uv_lines); | |
+ | |
+ /* can't use avpicture_alloc due UV height must be aligned by 32 */ | |
+ c4->conv_input.data[0] = av_malloc(c4->enc.inputFrameLen); | |
+ c4->conv_input.linesize[1] = c4->conv_input.linesize[0]; | |
+ c4->conv_input.data[1] = c4->conv_input.data[0] + c4->conv_input.linesize[0] * c4->conv_lines; | |
+ | |
+ c4->conv_output.data[0] = av_malloc(c4->enc.inputFrameLen); | |
+ c4->conv_output.linesize[0] = c4->conv_input.linesize[0]; | |
+ c4->conv_output.linesize[1] = c4->conv_input.linesize[1]; | |
+ c4->conv_output.data[1] = c4->conv_output.data[0] + c4->conv_output.linesize[0] * c4->conv_lines; | |
+ | |
+ /* allocate place for image converter input & output */ | |
+ if(!c4->conv_input.data[0] || !c4->conv_output.data[0]){ | |
+ av_log(avctx, AV_LOG_ERROR, "can't allocate picture converter"); | |
+ goto CrusherEnc_init_fail; | |
+ } | |
+ | |
+#ifdef CRUSHER_EXTRA_DEBUG | |
+ av_log(avctx, AV_LOG_DEBUG, "converter: newsize:%dx%d uv:%dx%d framelen: %d\n", | |
+ c4->conv_input.linesize[0], c4->conv_lines, | |
+ c4->conv_input.linesize[0], c4->conv_uv_lines, | |
+ c4->enc.inputFrameLen); | |
+#endif | |
+ avctx->coded_frame = avcodec_alloc_frame(); ///< Set up the output AVFrame | |
+ c4->curr_block = 0; | |
+ | |
+ if(!crusher_start(&c4->enc)){ | |
+ av_log(avctx, AV_LOG_ERROR, "starting codec device failed"); | |
+ goto CrusherEnc_init_fail; | |
+ } | |
+ | |
+ if(encode_dummy_gops(avctx) < 0){ | |
+ av_log(avctx, AV_LOG_ERROR, "encoding dummy GOP failed"); | |
+ goto CrusherEnc_init_fail; | |
+ } | |
+ | |
+ if(!c4->sps_pps_size) { | |
+ av_log(avctx, AV_LOG_ERROR, "codec don't send SPS/PPS, failed"); | |
+ goto CrusherEnc_init_fail; | |
+ } | |
+ | |
+ /* extradata received */ | |
+ if (avctx->flags & CODEC_FLAG_GLOBAL_HEADER) { | |
+ avctx->extradata_size = c4->sps_pps_size; | |
+ avctx->extradata = av_malloc(c4->sps_pps_size); | |
+ memcpy(avctx->extradata, c4->sps_pps, c4->sps_pps_size); | |
+ av_log(avctx, AV_LOG_DEBUG, "codec extradata: %d bytes\n", c4->sps_pps_size); | |
+ } | |
+ return 0; | |
+ | |
+CrusherEnc_init_fail: | |
+ crusher_close(&c4->enc); | |
+ avpicture_free(&c4->conv_input); | |
+ avpicture_free(&c4->conv_output); | |
+ return -1; | |
+} | |
+ | |
+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, | |
+ .supported_framerates= (const AVRational[]){{2500,100}, {3000,100}, {0,0}}, | |
+ .pix_fmts = (const enum PixelFormat[]) { PIX_FMT_NV12, PIX_FMT_NONE }, | |
+ .long_name = NULL_IF_CONFIG_SMALL("libcrusher264 H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10 (Hardwared)"), | |
+}; | |
diff --git a/libavdevice/Makefile b/libavdevice/Makefile | |
index 1c0630b..23f886f 100644 | |
--- a/libavdevice/Makefile | |
+++ b/libavdevice/Makefile | |
@@ -13,6 +13,7 @@ OBJS-$(CONFIG_ALSA_INDEV) += alsa-audio-common.o \ | |
OBJS-$(CONFIG_ALSA_OUTDEV) += alsa-audio-common.o \ | |
alsa-audio-enc.o | |
OBJS-$(CONFIG_BKTR_INDEV) += bktr.o | |
+OBJS-$(CONFIG_CRUSHERCAP_INDEV) += crushercap.o | |
OBJS-$(CONFIG_DV1394_INDEV) += dv1394.o | |
OBJS-$(CONFIG_JACK_INDEV) += jack_audio.o | |
OBJS-$(CONFIG_OSS_INDEV) += oss_audio.o | |
diff --git a/libavdevice/alldevices.c b/libavdevice/alldevices.c | |
index de3bc82..9f6c0c1 100644 | |
--- a/libavdevice/alldevices.c | |
+++ b/libavdevice/alldevices.c | |
@@ -41,6 +41,7 @@ void avdevice_register_all(void) | |
/* devices */ | |
REGISTER_INOUTDEV (ALSA, alsa); | |
REGISTER_INDEV (BKTR, bktr); | |
+ REGISTER_INDEV (CRUSHERCAP, crushercap); | |
REGISTER_INDEV (DV1394, dv1394); | |
REGISTER_INDEV (JACK, jack); | |
REGISTER_INOUTDEV (OSS, oss); | |
diff --git a/libavdevice/crushercap.c b/libavdevice/crushercap.c | |
new file mode 100644 | |
index 0000000..1466b69 | |
--- /dev/null | |
+++ b/libavdevice/crushercap.c | |
@@ -0,0 +1,391 @@ | |
+/* | |
+ * Linux CrusherCapture (MG1264) interface | |
+ * Copyright (c) 2010 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 | |
+ */ | |
+ | |
+#include "config.h" | |
+#include <unistd.h> | |
+#include <fcntl.h> | |
+#include <errno.h> | |
+#include <poll.h> | |
+#include <sys/ioctl.h> | |
+#include <sys/mman.h> | |
+#include <sys/time.h> | |
+#include <time.h> | |
+#include <strings.h> | |
+ | |
+#include <crusher264/crusher.h> | |
+#include "libavformat/avformat.h" | |
+#include "libavformat/qbox.h" | |
+#include "libavcodec/mpeg4audio.h" | |
+ | |
+#undef CRUSHERCAP_EXTRA_DEBUG | |
+//#define CRUSHERCAP_EXTRA_DEBUG | |
+ | |
+/* wrapping issue workaround: | |
+ * originally pts have only 32 bits, but due fast (~20 hours) filling | |
+ * additional counter used */ | |
+#define CRUSHERCAP_EXTRA_PTS | |
+ | |
+ | |
+struct crusherCap_data { | |
+ crusher_t crusher; | |
+ int qboxes_used; | |
+ qboxContext qbox; ///< qbox demuxing context | |
+ MPEG4AudioConfig cfg; | |
+#ifdef CRUSHERCAP_EXTRA_PTS | |
+ int64_t extra_pts; | |
+ uint32_t last_sample_cts; | |
+#endif | |
+}; | |
+ | |
+/** device initialization: | |
+ * - start device | |
+ * - read additional parameters from input string, and set up them | |
+ * - read extradata for h264/aac streams | |
+ * - parse aac-asc and set audio parameters | |
+ * - set time_base for a/v streams | |
+ */ | |
+static int crushercap_read_header(AVFormatContext * s, AVFormatParameters * ap) | |
+{ | |
+ struct crusherCap_data *ccap = s->priv_data; | |
+ AVStream *st; | |
+ int ret = CODEC_FAIL; | |
+ char *inparams_ptr, *str_ptr, *inparams = NULL; | |
+ int got_audio=0; | |
+ int got_video=0; | |
+ | |
+#ifdef CRUSHERCAP_EXTRA_DEBUG | |
+ av_log(s, AV_LOG_DEBUG, "loading defaults\n"); | |
+#endif | |
+ crusher_defaults(&ccap->crusher); | |
+ | |
+ | |
+ if( !crusher_find_device(&ccap->crusher, 1) ) { | |
+ av_log(s, AV_LOG_ERROR, "device not found\n"); | |
+ goto failed; | |
+ } | |
+ | |
+ if (ccap->crusher.devtype != DEV_TYPE_CAPTURE) { | |
+ av_log(s, AV_LOG_ERROR, "it's not capture device\n"); | |
+ goto failed; | |
+ } | |
+ | |
+ if (ap->channels <= 0) { | |
+ av_log(s, AV_LOG_ERROR, "Bad channels number %d\n", ap->channels); | |
+ goto failed; | |
+ } | |
+ | |
+ if (ap->sample_rate <= 0) { | |
+ av_log(s, AV_LOG_ERROR, "Bad channels samplerate %d\n", ap->sample_rate); | |
+ goto failed; | |
+ } | |
+ | |
+ ccap->crusher.framerate_num = 90000; | |
+ if (ap->standard && !strcasecmp(ap->standard, "ntsc")) { | |
+ ccap->crusher.framerate_den = 3003; | |
+ } else { | |
+ ccap->crusher.framerate_den = 3600; | |
+ } | |
+ | |
+ if (ap->channel && ap->channel < 3) { | |
+ ccap->crusher.video_input = ap->channel; | |
+ } else { | |
+ ccap->crusher.video_input = CAPTURE_INPUT_COMPOSITE; | |
+ } | |
+ | |
+ if(ap->width && ap->height) { | |
+ ccap->crusher.width = ap->width; | |
+ ccap->crusher.height = ap->height; | |
+ } | |
+ | |
+ ccap->crusher.audio_samplerate = ap->sample_rate; | |
+ ccap->crusher.audio_channels = ap->channels; | |
+ ccap->crusher.devmode = DEV_TYPE_CAPTURE; | |
+ ccap->crusher.out_format = OUT_FORMAT_QBOX; | |
+ ccap->crusher.rc_size = 35000000; | |
+ ccap->crusher.scenecut_threshold = 0; | |
+ ccap->crusher.deblock = 0; | |
+ ccap->crusher.bitrate_mode = BITRATE_MODE_MEDIUM; | |
+ | |
+ /* get additional parameters from "-i" argument */ | |
+ inparams = av_strdup(s->filename); | |
+ inparams_ptr = strtok (inparams, ":"); | |
+ while (inparams_ptr) { | |
+ str_ptr = strchr(inparams_ptr, '='); | |
+ if(str_ptr && strlen(inparams_ptr) > strlen(str_ptr)) { | |
+ *str_ptr='\0'; | |
+ str_ptr++; | |
+ av_log(s, AV_LOG_DEBUG, "inparams: param:\"%s\", value:\"%s\"\n", inparams_ptr, str_ptr); | |
+ if(!strcmp(inparams_ptr, "devnum") || !strcmp(inparams_ptr, "d")) { | |
+ ccap->crusher.devnum = atoi(str_ptr); | |
+ } else if (!strcmp(inparams_ptr, "bitrate") || !strcmp(inparams_ptr, "b")) { | |
+ ccap->crusher.bitrate = atoi(str_ptr); | |
+ if(ccap->crusher.bitrate >= 2000000) | |
+ ccap->crusher.bitrate_mode = BITRATE_MODE_HIGH; | |
+ } else if (!strcmp(inparams_ptr, "abitrate") || !strcmp(inparams_ptr, "ab")) { | |
+ ccap->crusher.audio_bitrate = atoi(str_ptr); | |
+ | |
+ /* audio codec selector */ | |
+ } else if (!strcmp(inparams_ptr, "acodec") && !strcmp(str_ptr, "pcm")) { | |
+ ccap->crusher.audio_codec = AUDIO_CODEC_PCM; | |
+ } else if (!strcmp(inparams_ptr, "acodec") && !strcmp(str_ptr, "aac")) { | |
+ ccap->crusher.audio_codec = AUDIO_CODEC_AAC; | |
+ } else if (!strcmp(inparams_ptr, "acodec") && !strcmp(str_ptr, "mp2")) { | |
+ ccap->crusher.audio_codec = AUDIO_CODEC_MP2; | |
+ av_log(s, AV_LOG_WARNING, "crushercap mp2 still not working\n"); | |
+ } else { | |
+ av_log(s, AV_LOG_ERROR, "Bad input parameter: %s\n" | |
+ "Avaliable parameters:\n" | |
+ "devnum [d] - device number\n" | |
+ "bitrate [b] - video bitrate\n" | |
+ "abitrate [ab] - audio bitrate (no matter for pcm)\n" | |
+ "acodec - audio codec (aac,pcm,mp2 default:aac)\n", inparams_ptr); | |
+ av_free(inparams); | |
+ goto failed; | |
+ } | |
+ | |
+ } | |
+ inparams_ptr = strtok (NULL, ":"); | |
+ } | |
+ av_free(inparams); | |
+ | |
+#ifdef CRUSHERCAP_EXTRA_DEBUG | |
+ av_log(s, AV_LOG_DEBUG, "i:%d ac:%d, ab:%d, ar:%d, b:%d, s:%dx%d r:%d/%d\n", | |
+ ccap->crusher.video_input, ccap->crusher.audio_channels, ccap->crusher.audio_bitrate, | |
+ ccap->crusher.audio_samplerate, | |
+ ccap->crusher.bitrate, | |
+ ccap->crusher.width, ccap->crusher.height, ccap->crusher.framerate_num, ccap->crusher.framerate_den); | |
+#endif | |
+ | |
+ if( !crusher_init_device(&ccap->crusher) ) { | |
+ av_log(s, AV_LOG_ERROR, "init failed"); | |
+ goto failed; | |
+ } | |
+ | |
+ if( !crusher_send_textconfig(&ccap->crusher) ) { | |
+ av_log(s, AV_LOG_ERROR, "sending textconfig failed"); | |
+ goto failed; | |
+ } | |
+ | |
+ if( !crusher_start(&ccap->crusher)){ | |
+ av_log(s, AV_LOG_ERROR, "starting device failed"); | |
+ goto failed; | |
+ } | |
+ | |
+ /* get extradata for a/v */ | |
+ do { | |
+ ret = crusher_encode(&ccap->crusher, NULL, 0); | |
+ if (ret == CODEC_FLUSHED && ccap->crusher.out_blocks) { | |
+ | |
+ for(ccap->qboxes_used=0; ccap->qboxes_used < ccap->crusher.out_blocks; ccap->qboxes_used++) { | |
+ if(ff_qbox_parse(&ccap->qbox, ccap->crusher.out_data[ccap->qboxes_used].data, | |
+ ccap->crusher.out_data[ccap->qboxes_used].len)) { | |
+ | |
+ /* if no more configs, return */ | |
+ if(got_video && got_audio) | |
+ return 0; | |
+ | |
+ switch(ccap->qbox.sample_stream_type){ | |
+ case SAMPLE_TYPE_AAC: | |
+ if (!(st = av_new_stream(s, 1))) | |
+ return AVERROR(ENOMEM); | |
+ | |
+ st->codec->codec_type = CODEC_TYPE_AUDIO; | |
+ st->codec->codec_id = CODEC_ID_AAC; | |
+ st->codec->extradata_size = ccap->qbox.qbox_size; | |
+ st->codec->extradata = av_malloc(st->codec->extradata_size); | |
+ memcpy(st->codec->extradata, ccap->qbox.data, ccap->qbox.qbox_size); | |
+ ff_mpeg4audio_get_config(&ccap->cfg, st->codec->extradata, | |
+ st->codec->extradata_size); | |
+ st->codec->channels = ccap->cfg.channels; | |
+ st->codec->sample_rate = ccap->cfg.sample_rate; | |
+ ap->sample_rate = ccap->cfg.sample_rate; | |
+ st->codec->bit_rate = ccap->crusher.audio_bitrate; | |
+ st->codec->sample_fmt = SAMPLE_FMT_S16; | |
+ st->codec->frame_size = 1024; | |
+ got_audio=1; | |
+ break; | |
+ | |
+ case SAMPLE_TYPE_PCM: | |
+ if (!(st = av_new_stream(s, 1))) | |
+ return AVERROR(ENOMEM); | |
+ | |
+ st->codec->codec_type = CODEC_TYPE_AUDIO; | |
+ st->codec->codec_id = CODEC_ID_PCM_S16BE; | |
+ st->codec->channels = ccap->crusher.audio_channels; | |
+ st->codec->sample_rate = ccap->crusher.audio_samplerate; | |
+ ap->sample_rate = ccap->crusher.audio_samplerate; | |
+ st->codec->sample_fmt = SAMPLE_FMT_S16; | |
+ got_audio=1; | |
+ break; | |
+ | |
+ case SAMPLE_TYPE_QMA: | |
+ if (!(st = av_new_stream(s, 1))) | |
+ return AVERROR(ENOMEM); | |
+ | |
+ st->codec->codec_type = CODEC_TYPE_AUDIO; | |
+ st->codec->codec_id = CODEC_ID_MP2; | |
+ st->codec->channels = ccap->crusher.audio_channels; | |
+ st->codec->sample_rate = ccap->crusher.audio_samplerate; | |
+ ap->sample_rate = ccap->crusher.audio_samplerate; | |
+ st->codec->sample_fmt = SAMPLE_FMT_S16; | |
+ got_audio=1; | |
+ break; | |
+ | |
+ case SAMPLE_TYPE_H264: | |
+ if (!(st = av_new_stream(s, 0))) | |
+ return AVERROR(ENOMEM); | |
+ st->codec->codec_type = CODEC_TYPE_VIDEO; | |
+ st->codec->codec_id = CODEC_ID_H264; | |
+ st->codec->extradata_size = ccap->qbox.qbox_size; | |
+ st->codec->extradata = av_malloc(st->codec->extradata_size); | |
+ st->codec->bit_rate = ccap->crusher.bitrate; | |
+ ff_qbox_make_startcode(ccap->qbox.data, ccap->qbox.qbox_size); | |
+ memcpy(st->codec->extradata, ccap->qbox.data, ccap->qbox.qbox_size); | |
+ got_video=1; | |
+ /* TODO: set aspect ratio */ | |
+ break; | |
+ | |
+ default: | |
+ av_log(s, AV_LOG_ERROR, "unknown qbox\n"); | |
+ goto failed; | |
+ break; | |
+ } | |
+ | |
+#ifdef CRUSHERCAP_EXTRA_PTS | |
+ av_set_pts_info(st, 64, 1, ccap->crusher.framerate_num); | |
+#else | |
+ av_set_pts_info(st, 32, 1, ccap->crusher.framerate_num); | |
+#endif | |
+ } else { | |
+ av_log(s, AV_LOG_ERROR, "bad qbox"); | |
+ goto failed; | |
+ } | |
+ } | |
+ } | |
+ } while ((ret == CODEC_FLUSHED ||ret == CODEC_FRAME_SENT) && ret != CODEC_FAIL); | |
+ return 0; | |
+ | |
+failed: | |
+ crusher_close(&ccap->crusher); | |
+ return AVERROR(EIO); | |
+} | |
+ | |
+/** reading qboxes from device (each event have 0-6 qboxes), | |
+ * if no qboxes left in buffer, then crusher_encode until get some event | |
+ */ | |
+static int crushercap_read_packet(AVFormatContext *s, AVPacket *pkt) | |
+{ | |
+ struct crusherCap_data *ccap = s->priv_data; | |
+ int ret = CODEC_FAIL; | |
+ | |
+ if(ccap->qboxes_used >= ccap->crusher.out_blocks) { | |
+ do { | |
+ ret = crusher_encode(&ccap->crusher, NULL, 0); | |
+ } while (ret != CODEC_FAIL && (ret != CODEC_FLUSHED || !ccap->crusher.out_blocks)); | |
+ | |
+ if (ret != CODEC_FLUSHED) | |
+ return -1; | |
+ ccap->qboxes_used=0; | |
+ } | |
+ | |
+#ifdef CRUSHERCAP_EXTRA_DEBUG | |
+ av_log(s, AV_LOG_DEBUG, "parsing qbox %d/%d\n", ccap->qboxes_used, ccap->crusher.out_blocks); | |
+#endif | |
+ if(ff_qbox_parse(&ccap->qbox, ccap->crusher.out_data[ccap->qboxes_used].data, | |
+ ccap->crusher.out_data[ccap->qboxes_used].len)) { | |
+#ifdef CRUSHERCAP_EXTRA_DEBUG | |
+ av_log(s, AV_LOG_DEBUG, "QBOX: sst:0x%08x sf:0x%08x pl:%u ts:%u\n", | |
+ ccap->qbox.sample_stream_type, ccap->qbox.sample_flags, ccap->qbox.qbox_size, ccap->qbox.sample_cts); | |
+#endif | |
+ /* if no more configs, return */ | |
+ if((ccap->qbox.sample_flags & SAMPLE_FLAGS_CONFIGURATION_INFO) || !(ccap->qbox.sample_flags & SAMPLE_FLAGS_CTS_PRESENT)) { | |
+ av_log(s, AV_LOG_ERROR, "stream config in the middle?\n"); | |
+ return -1; | |
+ } | |
+ | |
+ switch(ccap->qbox.sample_stream_type) { | |
+ case SAMPLE_TYPE_H264: | |
+ ff_qbox_make_startcode(ccap->qbox.data, ccap->qbox.qbox_size); | |
+ /* if no global header: add SPS/PPS to IDR */ | |
+ if (!(s->flags & CODEC_FLAG_GLOBAL_HEADER) && (ccap->qbox.sample_flags & SAMPLE_FLAGS_SYNC_POINT)) { | |
+ memmove(ccap->qbox.data + s->streams[0]->codec->extradata_size, | |
+ ccap->qbox.data, ccap->qbox.qbox_size); | |
+ memcpy(ccap->qbox.data, s->streams[0]->codec->extradata, s->streams[0]->codec->extradata_size); | |
+ ccap->qbox.qbox_size += s->streams[0]->codec->extradata_size; | |
+ } | |
+ av_init_packet(pkt); | |
+ pkt->stream_index = 0; | |
+ break; | |
+ case SAMPLE_TYPE_AAC: | |
+ case SAMPLE_TYPE_PCM: | |
+ case SAMPLE_TYPE_QMA: | |
+ av_init_packet(pkt); | |
+ pkt->stream_index = 1; | |
+ break; | |
+ default: | |
+ av_log(s, AV_LOG_ERROR, "unknown qbox : 0x%08x", ccap->qbox.sample_stream_type); | |
+ return -1; | |
+ break; | |
+ } | |
+ | |
+ pkt->data = ccap->qbox.data; | |
+ pkt->size = ccap->qbox.qbox_size; | |
+ pkt->flags |= ccap->qbox.sample_flags & SAMPLE_FLAGS_SYNC_POINT ? PKT_FLAG_KEY : 0; | |
+ | |
+ if(ccap->qbox.sample_flags & SAMPLE_FLAGS_CTS_PRESENT) { | |
+ pkt->pts = ccap->qbox.sample_cts; | |
+#ifdef CRUSHERCAP_EXTRA_PTS | |
+ if(ccap->qbox.sample_cts < ccap->last_sample_cts) | |
+ ccap->extra_pts += 0x100000000; | |
+ ccap->last_sample_cts = ccap->qbox.sample_cts; | |
+ pkt->pts += ccap->extra_pts; | |
+#endif | |
+ } else { | |
+ pkt->pts = AV_NOPTS_VALUE; | |
+ } | |
+ | |
+ ccap->qboxes_used++; | |
+ return pkt->size; | |
+ } else { | |
+ av_log(s, AV_LOG_ERROR, "bad qbox"); | |
+ return -1; | |
+ } | |
+ ccap->qboxes_used++; | |
+ return 0; | |
+} | |
+ | |
+ | |
+static int crushercap_close(AVFormatContext * context) | |
+{ | |
+ struct crusherCap_data *ccap = context->priv_data; | |
+ crusher_close(&ccap->crusher); | |
+ return 0; | |
+} | |
+ | |
+AVInputFormat crushercap_demuxer = { | |
+ .name = "crushercap", | |
+ .long_name = NULL_IF_CONFIG_SMALL("MG1264 CrusherCapture A/V grab"), | |
+ .priv_data_size = sizeof(struct crusherCap_data), | |
+ .read_header = crushercap_read_header, | |
+ .read_packet = crushercap_read_packet, | |
+ .read_close = crushercap_close, | |
+ .flags = AVFMT_NOFILE | |
+}; | |
diff --git a/libavformat/Makefile b/libavformat/Makefile | |
index 2ba8b09..1f8a9f9 100644 | |
--- a/libavformat/Makefile | |
+++ b/libavformat/Makefile | |
@@ -207,6 +207,7 @@ OBJS-$(CONFIG_PCM_U32LE_MUXER) += pcmenc.o rawenc.o | |
OBJS-$(CONFIG_PCM_U8_DEMUXER) += pcmdec.o pcm.o rawdec.o | |
OBJS-$(CONFIG_PCM_U8_MUXER) += pcmenc.o rawenc.o | |
OBJS-$(CONFIG_PVA_DEMUXER) += pva.o | |
+OBJS-$(CONFIG_QBOX_DEMUXER) += qbox.o | |
OBJS-$(CONFIG_QCP_DEMUXER) += qcp.o | |
OBJS-$(CONFIG_R3D_DEMUXER) += r3d.o | |
OBJS-$(CONFIG_RAWVIDEO_DEMUXER) += rawvideodec.o rawdec.o | |
diff --git a/libavformat/allformats.c b/libavformat/allformats.c | |
index 9f33e31..f654c88 100644 | |
--- a/libavformat/allformats.c | |
+++ b/libavformat/allformats.c | |
@@ -171,6 +171,7 @@ void av_register_all(void) | |
REGISTER_MUXDEMUX (PCM_U8, pcm_u8); | |
REGISTER_MUXER (PSP, psp); | |
REGISTER_DEMUXER (PVA, pva); | |
+ REGISTER_DEMUXER (QBOX, qbox); | |
REGISTER_DEMUXER (QCP, qcp); | |
REGISTER_DEMUXER (R3D, r3d); | |
REGISTER_MUXDEMUX (RAWVIDEO, rawvideo); | |
diff --git a/libavformat/qbox.c b/libavformat/qbox.c | |
new file mode 100644 | |
index 0000000..b4f8033 | |
--- /dev/null | |
+++ b/libavformat/qbox.c | |
@@ -0,0 +1,278 @@ | |
+/* | |
+ * Mobilygen/Maxim QBOX demuxer | |
+ * | |
+ * This file is part of FFmpeg. | |
+ * | |
+ * FFmpeg is free software; you can redistribute it and/or | |
+ * modify it under the terms of the GNU Lesser General Public | |
+ * License as published by the Free Software Foundation; either | |
+ * version 2.1 of the License, or (at your option) any later version. | |
+ * | |
+ * FFmpeg is distributed in the hope that it will be useful, | |
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
+ * Lesser General Public License for more details. | |
+ * | |
+ * You should have received a copy of the GNU Lesser General Public | |
+ * License along with FFmpeg; if not, write to the Free Software | |
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
+ */ | |
+ | |
+#include "libavutil/intreadwrite.h" | |
+#include "avformat.h" | |
+#include "qbox.h" | |
+#include "libavcodec/bytestream.h" | |
+#include "libavutil/bswap.h" | |
+#include "libavcodec/bytestream.h" | |
+#include "libavcodec/mpeg4audio.h" | |
+ | |
+#undef QBOX_EXTRA_DEBUG | |
+ | |
+typedef struct qboxDemux { | |
+ qboxContext qbox; | |
+ int fr_num; | |
+ int fr_den; | |
+ int from_header; | |
+ int got_audio; | |
+ int got_video; | |
+} qboxDemux; | |
+ | |
+/* | |
+ * The following functions constitute our interface to the world | |
+ */ | |
+ | |
+/* parse first 6x4 bytes of header | |
+ * TODO: parse headers with extensions (may be longer) | |
+ * | |
+ */ | |
+int ff_qbox_parse(qboxContext *qbox, uint8_t *input_data, int data_size) | |
+{ | |
+ const uint8_t *src = input_data; | |
+ | |
+ if(data_size < QBOX_HDR_SIZE) | |
+ return 0; | |
+ | |
+ | |
+ qbox->qbox_size = bytestream_get_be32(&src); | |
+ if(qbox->qbox_size < QBOX_HDR_SIZE) | |
+ return 0; | |
+ | |
+ qbox->qbox_size-=QBOX_HDR_SIZE; | |
+ bytestream_get_be32(&src); //qbox | |
+ qbox->version = bytestream_get_byte(&src); | |
+ qbox->boxflags = bytestream_get_be24(&src); | |
+ qbox->sample_stream_type = bytestream_get_be16(&src); | |
+ qbox->sample_stream_id = bytestream_get_be16(&src); | |
+ qbox->sample_flags = bytestream_get_be32(&src); | |
+ qbox->sample_cts = bytestream_get_be32(&src); | |
+ qbox->data = input_data + QBOX_HDR_SIZE; | |
+ return qbox->qbox_size; | |
+} | |
+ | |
+/** create h264 startcodes (by default there's nalu lengths in uint32_be format) | |
+ */ | |
+int ff_qbox_make_startcode(uint8_t *ptr, int input_data) | |
+{ | |
+ uint32_t size; | |
+ uint8_t *ptr_tmp = ptr; | |
+ while (ptr_tmp - ptr < input_data - 4) { | |
+ size = av_be2ne32(*(uint32_t *) ptr_tmp); | |
+ ptr_tmp[0] = 0x00; | |
+ ptr_tmp[1] = 0x00; | |
+ ptr_tmp[2] = 0x00; | |
+ ptr_tmp[3] = 0x01; | |
+ ptr_tmp+=4+size; | |
+ } | |
+ return 1; | |
+} | |
+ | |
+ | |
+/* | |
+ * demuxer probe: | |
+ * first 4 bytes of every qbox - is full qbox length | |
+ * next 4 bytes - chars "qbox", try find them | |
+ */ | |
+static int qbox_probe(AVProbeData * p) { | |
+ const uint8_t *d; | |
+ d = p->buf; | |
+ if (d[4] == 'q' && d[5] == 'b' && d[6] == 'o' && d[7] == 'x' ) { | |
+ return AVPROBE_SCORE_MAX; | |
+ } | |
+ return 0; | |
+} | |
+ | |
+/* | |
+ * probably there's no header, just stream with qboxes, | |
+ * if qbox flagged with CONFIGURATION_INFO, there's chance to get AudioSpecificConfig or SPS/PPS | |
+ * frames skipped until both audio & video seen | |
+ * */ | |
+static int qbox_read_header(AVFormatContext *s, AVFormatParameters *ap) { | |
+ qboxDemux *d = s->priv_data; | |
+ qboxContext *c = &d->qbox; | |
+ ByteIOContext *pb = s->pb; | |
+ MPEG4AudioConfig cfg; | |
+ AVStream *st; | |
+ uint8_t qbox_header[QBOX_HDR_SIZE]; | |
+ | |
+ | |
+ do { | |
+ if(d->got_audio && d->got_video) | |
+ return 0; | |
+ | |
+ if(!get_buffer(pb, qbox_header, QBOX_HDR_SIZE)) | |
+ return AVERROR(EIO); | |
+ | |
+ if(!ff_qbox_parse(c, qbox_header, QBOX_HDR_SIZE)) | |
+ return AVERROR(EIO); | |
+ | |
+ switch (c->sample_stream_type) { | |
+ case SAMPLE_TYPE_AAC: | |
+ if (c->sample_flags & SAMPLE_FLAGS_CONFIGURATION_INFO) { | |
+ if (!(st = av_new_stream(s, 1))) | |
+ return AVERROR(ENOMEM); | |
+ st->codec->codec_type = CODEC_TYPE_AUDIO; | |
+ st->codec->codec_id = CODEC_ID_AAC; | |
+ st->codec->extradata_size = c->qbox_size; | |
+ st->codec->extradata = av_malloc(st->codec->extradata_size); | |
+ get_buffer(pb, st->codec->extradata, st->codec->extradata_size); | |
+ ff_mpeg4audio_get_config(&cfg, st->codec->extradata, | |
+ st->codec->extradata_size); | |
+ st->codec->channels = cfg.channels; | |
+ st->codec->sample_rate = cfg.sample_rate; | |
+ | |
+ /* need to set form external */ | |
+ if(ap->sample_rate == 25) { | |
+ av_set_pts_info(st, 32, 3600, 90000); | |
+ } else if(ap->sample_rate == 30) { | |
+ av_set_pts_info(st, 32, 3001, 90000); | |
+ } else { | |
+ av_set_pts_info(st, 32, 3600, 90000); // default | |
+ } | |
+ } | |
+ d->got_audio=1; | |
+ break; | |
+ case SAMPLE_TYPE_PCM: | |
+ if (!(st = av_new_stream(s, 1))) | |
+ return AVERROR(ENOMEM); | |
+ st->codec->codec_type = CODEC_TYPE_AUDIO; | |
+ st->codec->codec_id = CODEC_ID_PCM_S16BE; | |
+ /* this 3 parameters have to be set up by higher level functions */ | |
+ st->codec->channels = 2; | |
+ st->codec->sample_rate = 48000; | |
+ if(ap->sample_rate == 25) { | |
+ av_set_pts_info(st, 32, 3600, 90000); | |
+ } else if(ap->sample_rate == 30) { | |
+ av_set_pts_info(st, 32, 3001, 90000); | |
+ } else { | |
+ av_set_pts_info(st, 32, 3600, 90000); // default | |
+ } | |
+ url_fskip(pb, c->qbox_size); //TODO: use it too | |
+ d->got_audio=1; | |
+#ifdef QBOX_EXTRA_DEBUG | |
+ av_log(s, AV_LOG_DEBUG, "got_audio\n"); | |
+#endif | |
+ break; | |
+ case SAMPLE_TYPE_H264: | |
+ if (c->sample_flags & SAMPLE_FLAGS_CONFIGURATION_INFO) { | |
+ if (!(st = av_new_stream(s, 0))) | |
+ return AVERROR(ENOMEM); | |
+ st->codec->codec_type = CODEC_TYPE_VIDEO; | |
+ st->codec->codec_id = CODEC_ID_H264; | |
+ st->codec->extradata_size = c->qbox_size; | |
+ st->codec->extradata = av_malloc(st->codec->extradata_size); | |
+ get_buffer(pb, st->codec->extradata, st->codec->extradata_size); | |
+ ff_qbox_make_startcode(st->codec->extradata, st->codec->extradata_size); | |
+ /* TODO: set aspect ratio */ | |
+ if(ap->sample_rate == 25) { | |
+ av_set_pts_info(st, 32, 3600, 90000); | |
+ } else if(ap->sample_rate == 30) { | |
+ av_set_pts_info(st, 32, 3001, 90000); | |
+ } else { | |
+ av_set_pts_info(st, 32, 3600, 90000); ///< default | |
+ } | |
+ } | |
+ if(d->got_video==1) { | |
+ /* looks like qboxes without sound | |
+ * change pts info */ | |
+ av_set_pts_info(s->streams[0], 32, 2500, 100); | |
+ d->got_audio=1; | |
+ d->from_header=1; | |
+ } | |
+ /* audio detecting given chance, but got 2 frames of video, seems no audio... */ | |
+ | |
+ d->got_video=1; | |
+#ifdef QBOX_EXTRA_DEBUG | |
+ av_log(s, AV_LOG_DEBUG, "got_video\n"); | |
+#endif | |
+ break; | |
+ default: | |
+ av_log(s, AV_LOG_ERROR, "unknown qbox: s:%d t:0x%08x id:%08x f:%08x cts:%d\n", | |
+ c->qbox_size, c->sample_stream_type, c->sample_stream_id, c->sample_flags, c->sample_cts); | |
+ url_fskip(pb, c->qbox_size); | |
+ break; | |
+ } | |
+ } while(c->sample_flags & SAMPLE_FLAGS_CONFIGURATION_INFO); | |
+ return 0; | |
+} | |
+ | |
+ | |
+ | |
+/* | |
+ * extradata set, create packets from qboxes | |
+ * */ | |
+static int qbox_read_packet(AVFormatContext *s, AVPacket *pkt) { | |
+ qboxDemux *d = s->priv_data; | |
+ qboxContext *c = &d->qbox; | |
+ ByteIOContext *pb = s->pb; | |
+ uint8_t qbox_header[QBOX_HDR_SIZE]; | |
+ int ret = 0; | |
+ | |
+ if(!d->from_header) { | |
+ if(!get_buffer(pb, qbox_header, QBOX_HDR_SIZE)) | |
+ return AVERROR(EIO); | |
+ | |
+ if(!ff_qbox_parse(c, qbox_header, QBOX_HDR_SIZE)) | |
+ return AVERROR(EIO); | |
+ } else { | |
+ d->from_header=0; | |
+ } | |
+#ifdef QBOX_EXTRA_DEBUG | |
+ av_log(s, AV_LOG_DEBUG, "qbox: s:%d t:0x%08x id:%08x f:%08x cts:%d\n", | |
+ c->qbox_size, c->sample_stream_type, c->sample_stream_id, c->sample_flags, c->sample_cts); | |
+#endif | |
+ | |
+ if ((ret = av_get_packet(pb, pkt, c->qbox_size)) <= 0) | |
+ return AVERROR(EIO); | |
+ | |
+ pkt->dts = c->sample_cts; | |
+ if(c->sample_flags & SAMPLE_FLAGS_SYNC_POINT) | |
+ pkt->flags |= PKT_FLAG_KEY; | |
+ | |
+ | |
+ switch (c->sample_stream_type) { | |
+ case SAMPLE_TYPE_QMA: | |
+ case SAMPLE_TYPE_PCM: | |
+ case SAMPLE_TYPE_AAC: | |
+ pkt->stream_index = 1; | |
+ break; | |
+ case SAMPLE_TYPE_H264: | |
+ pkt->stream_index = 0; | |
+ ff_qbox_make_startcode(pkt->data, pkt->size); | |
+ break; | |
+ default: | |
+ av_log(s, AV_LOG_ERROR, "unknown qbox\n"); | |
+ return 0; | |
+ break; | |
+ } | |
+ return ret; | |
+} | |
+ | |
+ | |
+AVInputFormat qbox_demuxer = { | |
+ "qbox", | |
+ NULL_IF_CONFIG_SMALL("qbox raw format"), | |
+ sizeof(qboxDemux), | |
+ qbox_probe, | |
+ qbox_read_header, | |
+ qbox_read_packet, | |
+}; | |
diff --git a/libavformat/qbox.h b/libavformat/qbox.h | |
new file mode 100644 | |
index 0000000..45dc190 | |
--- /dev/null | |
+++ b/libavformat/qbox.h | |
@@ -0,0 +1,69 @@ | |
+/* | |
+ * Mobilygen/Maxim QBOX demuxer | |
+ * | |
+ * 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 | |
+ */ | |
+ | |
+#ifndef QBOX_H_ | |
+#define QBOX_H_ | |
+ | |
+#define QBOX_HDR_SIZE (6*4) | |
+ | |
+enum { | |
+ SAMPLE_TYPE_AAC = 0x1, | |
+ SAMPLE_TYPE_H264, | |
+ SAMPLE_TYPE_PCM, | |
+ SAMPLE_TYPE_DEBUG, | |
+ SAMPLE_TYPE_H264_SLICE, | |
+ SAMPLE_TYPE_QMA, | |
+ SAMPLE_TYPE_VIN_STATS_GLOBAL, | |
+ SAMPLE_TYPE_VIN_STATS_MB, | |
+ SAMPLE_TYPE_Q711, | |
+ SAMPLE_TYPE_Q728, | |
+ SAMPLE_TYPE_MAX, | |
+}; | |
+ | |
+ | |
+ | |
+#define SAMPLE_FLAGS_CONFIGURATION_INFO 0x01 | |
+#define SAMPLE_FLAGS_CTS_PRESENT 0x02 | |
+#define SAMPLE_FLAGS_SYNC_POINT 0x04 | |
+#define SAMPLE_FLAGS_DISPOSABLE 0x08 | |
+#define SAMPLE_FLAGS_MUTE 0x10 | |
+#define SAMPLE_FLAGS_BASE_CTS_INCREMENT 0x20 | |
+#define SAMPLE_FLAGS_META_INFO 0x40 | |
+#define SAMPLE_FLAGS_END_OF_SEQUENCE 0x80 | |
+#define SAMPLE_FLAGS_END_OF_STREAM 0x100 | |
+#define SAMPLE_FLAGS_PADDING_MASK 0xFF000000 | |
+ | |
+typedef struct qboxContext { | |
+ uint32_t qbox_size; ///< will be decreased | |
+ uint32_t boxflags; | |
+ uint8_t version; | |
+ uint16_t sample_stream_type; | |
+ uint16_t sample_stream_id; | |
+ uint32_t sample_flags; | |
+ uint32_t sample_cts; | |
+ uint8_t *data; | |
+} qboxContext; | |
+ | |
+int ff_qbox_parse(qboxContext *qbox, uint8_t *input_data, int data_size); | |
+int ff_qbox_make_startcode(uint8_t *ptr, int input_data); | |
+ | |
+ | |
+ | |
+#endif /* QBOX_H_ */ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Index: crusher264-config.in | |
=================================================================== | |
--- crusher264-config.in (revision 69) | |
+++ crusher264-config.in (working copy) | |
@@ -44,6 +44,7 @@ | |
--bindir) echo_bindir="yes" ;; | |
--sbindir) echo_sbindir="yes" ;; | |
--libexecdir) echo_libexecdir="yes" ;; | |
+ --datarootdir) echo_datarootdir="yes" ;; | |
--datadir) echo_datadir="yes" ;; | |
--sysconfdir) echo_sysconfdir="yes" ;; | |
--sharedstatedir) echo_sharedstatedir="yes" ;; | |
@@ -80,6 +81,9 @@ | |
if test -z "$libexecdir" ; then | |
libexecdir="@libexecdir@" | |
fi | |
+if test -z "$datarootdir" ; then | |
+ datarootdir="@datarootdir@" | |
+fi | |
if test -z "$datadir" ; then | |
datadir="@datadir@" | |
fi | |
@@ -160,6 +164,9 @@ | |
if test x$echo_libexecdir = xyes ; then | |
o=" $libexecdir" | |
fi | |
+if test x$echo_datarootdir = xyes ; then | |
+ o=" $datarootdir" | |
+fi | |
if test x$echo_datadir = xyes ; then | |
o=" $datadir" | |
fi | |
@@ -190,6 +197,9 @@ | |
if test x$echo_build = xyes ; then | |
o=" $build" | |
fi | |
+if test x$echo_pkgdatarootdir = xyes ; then | |
+ o=" ${datarootdir}/${package}" | |
+fi | |
if test x$echo_pkgdatadir = xyes ; then | |
o=" ${datadir}/${package}" | |
fi | |
@@ -236,6 +246,7 @@ | |
--bindir \$bindir $bindir | |
--sbindir \$sbindir $sbindir | |
--libexecdir \$libexecdir $libexecdir | |
+ --datarootdir \$datarootdir $datarootdir | |
--datadir \$datadir $datadir | |
--sysconfdir \$sysconfdir $sysconfdir | |
--sharedstatedir \$sharedstatedir$sharedstatedir | |
@@ -246,10 +257,11 @@ | |
--target \$target $target | |
--host \$host $host | |
--build \$build $build | |
- --pkgdatadir \$datadir/\$package ${datadir}/${package} | |
- --pkglibdir \$libdir/\$package ${libdir}/${package} | |
- --pkgincludedir \$includedir/\$package ${includedir}/${package} | |
- --template-version \$template_version $template_version | |
+ --pkgdatarootdir \$datarootdir/\$package ${datarootdir}/${package} | |
+ --pkgdatadir \$datadir/\$package ${datadir}/${package} | |
+ --pkglibdir \$libdir/\$package ${libdir}/${package} | |
+ --pkgincludedir \$includedir/\$package ${includedir}/${package} | |
+ --template-version \$template_version $template_version | |
--help | |
EOF | |
fi | |
Index: configure.ac | |
=================================================================== | |
--- configure.ac (revision 69) | |
+++ configure.ac (working copy) | |
@@ -242,8 +242,10 @@ | |
AC_DEFINE(HAVE_BSWAP) | |
;; | |
armv5*e*|arm[79]*e*|arm9[24]6*|arm96*|arm102[26]) | |
- CRUSHER264_CFLAGS+="-mv=5e" | |
- AC_DEFINE(ARCH_ARM) | |
+ #CRUSHER264_CFLAGS+="-mv=5e" | |
+ #For some reason this breaks ffmpeg 0.6.1 on the Dockstar | |
+ CRUSHER264_CFLAGS+="" | |
+ AC_DEFINE(ARCH_ARM) | |
;; | |
armv4*|arm7*|arm9[24]*) | |
CRUSHER264_CFLAGS+="-mv=4" | |
Index: src/crusher.c | |
=================================================================== | |
--- src/crusher.c (revision 69) | |
+++ src/crusher.c (working copy) | |
@@ -270,7 +270,7 @@ | |
switch(crusher->devtype) { | |
case DEV_TYPE_ENCODER: | |
- crusher->mg1264fw = MG1264_Firmware; | |
+ crusher->mg1264fw = MG1264Firmware; | |
crusher->framerate_num = 2500; | |
crusher->framerate_den = 100; | |
break; | |
@@ -297,7 +297,7 @@ | |
switch(devices[dev_type_id].devType) { | |
case DEV_TYPE_ENCODER: | |
- crusher->fx2fw = FX2_Firmware; | |
+ crusher->fx2fw = FX2Firmware; | |
break; | |
case DEV_TYPE_CAPTURE: | |
crusher->fx2fw = FX2_CaptureFirmware; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment