From 0e0e602fb4e80011871da9c44374ca8ee277e5bd Mon Sep 17 00:00:00 2001 From: Niels Elburg Date: Tue, 17 Oct 2006 22:12:44 +0000 Subject: [PATCH] added quicktime support to veejay-current git-svn-id: svn://code.dyne.org/veejay/trunk@639 eb8d1916-c9e9-0310-b8de-cf0c9472ead5 --- veejay-current/configure.ac | 11 + veejay-current/libel/Makefile.am | 3 +- veejay-current/libel/lav_io.c | 678 +++++++++++++++++++++++++---- veejay-current/libel/lav_io.h | 1 + veejay-current/libel/vj-el.c | 73 ++-- veejay-current/veejay/Makefile.am | 4 +- veejay-current/veejay/vj-perform.c | 1 + 7 files changed, 654 insertions(+), 117 deletions(-) diff --git a/veejay-current/configure.ac b/veejay-current/configure.ac index c0061e8c..542ca9e6 100644 --- a/veejay-current/configure.ac +++ b/veejay-current/configure.ac @@ -324,6 +324,16 @@ if test x$with_libdv != xno ; then [have_libdv=false]) fi +have_libquicktime=false +if test x$with_libquicktime != xno ; then + PKG_CHECK_MODULES(LIBQUICKTIME, [libquicktime > 0.9.7], + [have_libquicktime=true + AC_DEFINE(HAVE_LIBQUICKTIME, 1, [libquicktime > 0.9.7 prese +nt])], + [have_libquicktime=false]) +fi +AM_CONDITIONAL(HAVE_LIBQUICKTIME, test x$have_libquicktime = xtrue) + dnl ******************************************************************** @@ -969,6 +979,7 @@ fi AC_MSG_NOTICE([ - DirectFB support : ${have_directfb}]) AC_MSG_NOTICE([ - AVI MJPEG playback/recording : true (always)]) AC_MSG_NOTICE([ - libDV (digital video) support : ${have_libdv} ]) +AC_MSG_NOTICE([ - QuickTime support : ${have_libquicktime} ]) AC_MSG_NOTICE([ - FFmpeg AVFormat : ${have_avformat} ]) AC_MSG_NOTICE([ - FFmpeg AVCodec : ${have_avcodec} ]) AC_MSG_NOTICE([ - JPEG support : ${have_jpeg} ]) diff --git a/veejay-current/libel/Makefile.am b/veejay-current/libel/Makefile.am index 6bc7e8cd..84a940fa 100644 --- a/veejay-current/libel/Makefile.am +++ b/veejay-current/libel/Makefile.am @@ -4,7 +4,8 @@ MAINTAINERCLEANFILES = Makefile.in INCLUDES = -I$(top_srcdir) -I$(includedir) -I$(top_srcdir)/vjmem \ -I$(top_srcdir)/vjmsg \ - $(MJPEGTOOLS_CFLAGS) ${FFMPEG_CFLAGS} ${PIXBUF_CFLAGS} + $(MJPEGTOOLS_CFLAGS) ${FFMPEG_CFLAGS} ${PIXBUF_CFLAGS} \ + $(LIBQUICKTIME_CFLAGS) VJEL_LIB_FILE = libel.la noinst_LTLIBRARIES = $(VJEL_LIB_FILE) diff --git a/veejay-current/libel/lav_io.c b/veejay-current/libel/lav_io.c index e4825388..f23fed29 100644 --- a/veejay-current/libel/lav_io.c +++ b/veejay-current/libel/lav_io.c @@ -35,6 +35,15 @@ #ifdef USE_GDK_PIXBUF #include #endif +#include +#ifdef HAVE_LIBQUICKTIME +#include +#include +#include +#define QUICKTIME_MJPG_TAG 0x6d6a7067 +#endif + + extern int AVI_errno; static int _lav_io_default_chroma = CHROMAUNKNOWN; static char video_format=' '; @@ -55,6 +64,8 @@ static unsigned long jpeg_padded_len = 0; static unsigned long jpeg_app0_offset = 0; static unsigned long jpeg_app1_offset = 0; +uint16_t reorder_16(uint16_t todo, int big_endian); + #ifdef USE_GDK_PIXBUF static int output_scale_width = 0; static int output_scale_height = 0; @@ -85,6 +96,20 @@ void lav_set_project(int w, int h, float f, int fmt) #define M_APP1 0xE1 +#ifdef HAVE_LIBQUICKTIME +/* + put_int4: + Put a 4 byte integer value into a character array as big endian number +*/ + +static void put_int4(unsigned char *buf, int val) +{ + buf[0] = (val >> 24); + buf[1] = (val >> 16); + buf[2] = (val >> 8 ); + buf[3] = (val ); +} +#endif //#ifdef SUPPORT_READ_DV2 //static int check_DV2_input(lav_file_t *lav_fd); @@ -343,6 +368,27 @@ lav_file_t *lav_open_output_file(char *filename, char format, AVI_set_video(lav_fd->avi_fd,width,height,fps, "dvsd"); if(asize) AVI_set_audio(lav_fd->avi_fd,achans,arate,asize,WAVE_FORMAT_PCM); return lav_fd; + case 'q': +#ifdef HAVE_LIBQUICKTIME + /* open quicktime output file */ + + /* since the documentation says that the file should be empty, + we try to remove it first */ + + remove(filename); + + lav_fd->qt_fd = quicktime_open(filename, 0, 1); + if(!lav_fd->qt_fd) { free(lav_fd); return 0; } + quicktime_set_video(lav_fd->qt_fd, 1, width, height, fps, + (interlaced ? QUICKTIME_MJPA : QUICKTIME_JPEG)); + if (asize) + quicktime_set_audio(lav_fd->qt_fd, achans, arate, asize, QUICKTIME_TWOS); + return lav_fd; +#else + internal_error = ERROR_FORMAT; + return 0; +#endif + } if(lav_fd) free(lav_fd); return NULL; @@ -365,6 +411,11 @@ int lav_close(lav_file_t *lav_file) ret = 1; break; #endif +#ifdef HAVE_LIBQUICKTIME + case 'q': + ret = quicktime_close( lav_file->qt_fd ); + break; +#endif default: ret = AVI_close(lav_file->avi_fd); break; @@ -391,8 +442,49 @@ int lav_write_frame(lav_file_t *lav_file, uint8_t *buff, long size, long count) if(video_format == 'x') return -1; #endif - if(lav_file->interlacing!=LAV_NOT_INTERLACED && (lav_file->format == 'a' || lav_file->format=='A')) + if(lav_file->interlacing!=LAV_NOT_INTERLACED) { + switch( lav_file->format ) + { + case 'a': + case 'A': + jpgdata = buff; + jpglen = size; + + /* Loop over both fields */ + + for(n=0;n<2;n++) + { + /* For first field scan entire field, for second field + scan the JPEG header, put in AVI1 + polarity. + Be generous on errors */ + + res = scan_jpeg(jpgdata, size, n); + if (res) + { + internal_error=ERROR_JPEG; + return -1; + } + + if(!jpeg_app0_offset) continue; + + /* APP0 marker should be at least 14+2 bytes */ + if(get_int2(jpgdata+jpeg_app0_offset+2) < 16 ) continue; + + jpgdata[jpeg_app0_offset+4] = 'A'; + jpgdata[jpeg_app0_offset+5] = 'V'; + jpgdata[jpeg_app0_offset+6] = 'I'; + jpgdata[jpeg_app0_offset+7] = '1'; + jpgdata[jpeg_app0_offset+8] = lav_file->format=='a' ? n+1 : 2-n; + + /* Update pointer and len for second field */ + jpgdata += jpeg_padded_len; + jpglen -= jpeg_padded_len; + } + break; +#ifdef HAVE_LIBQUICKTIME + case 'q': + jpgdata = buff; jpglen = size; @@ -400,53 +492,104 @@ int lav_write_frame(lav_file_t *lav_file, uint8_t *buff, long size, long count) for(n=0;n<2;n++) { - /* For first field scan entire field, for second field - scan the JPEG header, put in AVI1 + polarity. - Be generous on errors */ + /* Scan the entire JPEG field data - APP1 marker MUST be present */ + res = scan_jpeg(jpgdata,jpglen,0); + if(res || !jpeg_app1_offset) { internal_error=ERROR_JPEG; return -1; } - res = scan_jpeg(jpgdata, size, n); - if (res) { internal_error=ERROR_JPEG; return -1; } + /* Length of APP1 marker must be at least 40 + 2 bytes */ + if ( get_int2(jpgdata+jpeg_app1_offset+2) < 42) + { internal_error=ERROR_JPEG; return -1; } - if(!jpeg_app0_offset) continue; - - /* APP0 marker should be at least 14+2 bytes */ - if(get_int2(jpgdata+jpeg_app0_offset+2) < 16 ) continue; - - jpgdata[jpeg_app0_offset+4] = 'A'; - jpgdata[jpeg_app0_offset+5] = 'V'; - jpgdata[jpeg_app0_offset+6] = 'I'; - jpgdata[jpeg_app0_offset+7] = '1'; - jpgdata[jpeg_app0_offset+8] = lav_file->format=='a' ? n+1 : 2-n; + /* Fill in data */ + put_int4(jpgdata+jpeg_app1_offset+ 4,0); + put_int4(jpgdata+jpeg_app1_offset+ 8,QUICKTIME_MJPG_TAG); + put_int4(jpgdata+jpeg_app1_offset+12,jpeg_field_size); + put_int4(jpgdata+jpeg_app1_offset+16,jpeg_padded_len); + put_int4(jpgdata+jpeg_app1_offset+20,n==0?jpeg_padded_len:0); + put_int4(jpgdata+jpeg_app1_offset+24,jpeg_quant_offset); + put_int4(jpgdata+jpeg_app1_offset+28,jpeg_huffman_offset); + put_int4(jpgdata+jpeg_app1_offset+32,jpeg_image_offset); + put_int4(jpgdata+jpeg_app1_offset+36,jpeg_scan_offset); + put_int4(jpgdata+jpeg_app1_offset+40,jpeg_data_offset); /* Update pointer and len for second field */ jpgdata += jpeg_padded_len; jpglen -= jpeg_padded_len; - } + } + break; +#endif + } - + } res = 0; /* Silence gcc */ for(n=0;nformat) + { + case 'a': + case 'A': if(n==0) res = AVI_write_frame( lav_file->avi_fd, buff, size ); else res = AVI_dup_frame( lav_file->avi_fd ); + break; + +#ifdef HAVE_LIBQUICKTIME + case 'q': + res = quicktime_write_frame( lav_file->qt_fd, buff, size, 0 ); + break; +#endif + default: + res = -1; + break; + + } } return res; } int lav_write_audio(lav_file_t *lav_file, uint8_t *buff, long samps) { - video_format = lav_file->format; internal_error = 0; /* for error messages */ + int res; +#ifdef HAVE_LIBQUICKTIME + int i, j; + int16_t *qt_audio = (int16_t *)buff, **qt_audion; + int channels = lav_audio_channels(lav_file); + + qt_audion = malloc(channels * sizeof (int16_t **)); + for (i = 0; i < channels; i++) + qt_audion[i] = (int16_t *)malloc(samps * lav_file->bps); +#endif + switch(lav_file->format ) + { +#ifdef HAVE_LIBQUICKTIME + case 'q': + /* Deinterleave the audio into the two channels. */ + for (i = 0; i < samps; i++) + { + for (j = 0; j < channels; j++) + qt_audion[j][i] = qt_audio[(channels*i) + j]; + } + res = lqt_encode_audio_track(lav_file->qt_fd, qt_audion, NULL,samps,0); + for (j = 0; j < channels; j++) + free(qt_audion[j]); + free(qt_audion); + return res; + break; +#endif #ifdef SUPPORT_READ_DV2 - if(video_format == 'b') - return 0; + case 'b': + return 0; #endif #ifdef USE_GDK_PIXBUF - if(video_format == 'x') - return 0; + case 'x': + return 0; #endif - return AVI_write_audio( lav_file->avi_fd, buff, samps*lav_file->bps); + case 'a': + case 'A': + return AVI_write_audio( lav_file->avi_fd, buff, samps*lav_file->bps); + } + return 0; } @@ -454,57 +597,97 @@ int lav_write_audio(lav_file_t *lav_file, uint8_t *buff, long samps) long lav_video_frames(lav_file_t *lav_file) { video_format = lav_file->format; internal_error = 0; /* for error messages */ + switch(lav_file->format) + { + case 'A': + case 'a': + return AVI_video_frames( lav_file->avi_fd ); #ifdef SUPPORT_READ_DV2 - if(video_format == 'b') - return rawdv_video_frames(lav_file->dv_fd); + case 'b': + return rawdv_video_frames(lav_file->dv_fd); #endif #ifdef USE_GDK_PIXBUF - if(video_format == 'x') - return 2; + case 'x': + return 2; #endif - return AVI_video_frames(lav_file->avi_fd); +#ifdef HAVE_LIBQUICKTIME + case 'q': + return quicktime_video_length(lav_file->qt_fd,0); +#endif + } + return -1; } int lav_video_width(lav_file_t *lav_file) { video_format = lav_file->format; internal_error = 0; /* for error messages */ + switch(lav_file->format) + { + case 'a': + case 'A': + return AVI_video_width(lav_file->avi_fd); #ifdef SUPPORT_READ_DV2 - if(video_format=='b') - return rawdv_width(lav_file->dv_fd); + case 'b': + return rawdv_width(lav_file->dv_fd); #endif #ifdef USE_GDK_PIXBUF - if(video_format=='x') - return (output_scale_width == 0 ? vj_picture_get_width( lav_file->picture ) : output_scale_width); + case 'x': + return (output_scale_width == 0 ? vj_picture_get_width( lav_file->picture ) : output_scale_width); #endif - return AVI_video_width(lav_file->avi_fd); +#ifdef HAVE_LIBQUICKTIME + case 'q': + return quicktime_video_width(lav_file->qt_fd,0); +#endif + } + return -1; } int lav_video_height(lav_file_t *lav_file) { video_format = lav_file->format; internal_error = 0; /* for error messages */ + switch( lav_file->format ) + { + case 'a': + case 'A': + return AVI_video_height(lav_file->avi_fd); #ifdef SUPPORT_READ_DV2 - if(video_format == 'b') - return rawdv_height( lav_file->dv_fd ); + case 'b': + return rawdv_height( lav_file->dv_fd ); #endif -#ifdef USE_GDK_PIXBUF - if(video_format == 'x') - return (output_scale_height == 0 ? vj_picture_get_height( lav_file->picture ) : output_scale_height); +#ifdef USE_GDK_PIXBUF + case 'x': + return (output_scale_height == 0 ? vj_picture_get_height( lav_file->picture ) : output_scale_height); #endif - return AVI_video_height(lav_file->avi_fd); +#ifdef HAVE_LIBQUICKTIME + case 'q': + return quicktime_video_height(lav_file->qt_fd,0); +#endif + } + return -1; } double lav_frame_rate(lav_file_t *lav_file) { video_format = lav_file->format; internal_error = 0; /* for error messages */ + switch(lav_file->format) + { + case 'a': + case 'A': + return AVI_frame_rate(lav_file->avi_fd); #ifdef SUPPORT_READ_DV2 - if(video_format == 'b') - return rawdv_fps(lav_file->dv_fd); + case 'b': + return rawdv_fps(lav_file->dv_fd); #endif #ifdef USE_GDK_PIXBUF - if(video_format == 'x') - return output_fps; + case 'x': + return output_fps; #endif - return AVI_frame_rate(lav_file->avi_fd); +#ifdef HAVE_LIBQUICKTIME + case 'q': + return quicktime_frame_rate(lav_file->qt_fd,0); +#endif + } + return -1; } int lav_video_interlacing(lav_file_t *lav_file) @@ -536,6 +719,78 @@ int lav_video_MJPG_chroma(lav_file_t *lav_file) { return lav_file->MJPG_chroma; } + +int lav_is_yuv_planar( int pix_fmt ) +{ + switch(pix_fmt){ + case PIX_FMT_YUVJ420P: + case PIX_FMT_YUVJ422P: + case PIX_FMT_YUVJ444P: + case PIX_FMT_YUV420P: + case PIX_FMT_YUV422P: + case PIX_FMT_YUV444P: + return 1; + } + return 0; +} + +int lav_video_cmodel( lav_file_t *lav_file) +{ +#ifdef HAVE_LIBQUICKTIME + if( lav_file->qt_fd ) + { + int cm = lqt_get_cmodel( lav_file->qt_fd,0 ); +// veejay_msg(0, "QT color model %d",cm); + switch(cm) + { + //@ seems not to work + // case BC_RGB888: + // return PIX_FMT_RGB24; + // case BC_BGR888: + // return PIX_FMT_BGR24; + case BC_YUV422P: + return PIX_FMT_YUV422P; + case BC_YUV422: + return PIX_FMT_YUV422; + case BC_YUV420P: + return PIX_FMT_YUV420P; + // case BC_YUVJ422P: + // return PIX_FMT_YUVJ422P; + // case BC_YUVJ420P: + // return PIX_FMT_YUVJ420P; + default: + return -1; + } + } +#endif + switch(lav_file->MJPG_chroma) + { + case CHROMA411: + return PIX_FMT_YUV411P; + case CHROMA420: + return PIX_FMT_YUV420P; + case CHROMA422: + return PIX_FMT_YUV422P; + case CHROMA444: + return PIX_FMT_YUV444P; + default: + return -1; + } + + return -1; +} + +int lav_video_is_qt( lav_file_t *lav_file) +{ +#ifdef HAVE_LIBQUICK_TIME + if( lav_file->qt_fd) + return 1; +#endif + return 0; +} + + + int lav_video_compressor_type(lav_file_t *lav_file) { #ifdef SUPPORT_READ_DV2 @@ -545,6 +800,36 @@ int lav_video_compressor_type(lav_file_t *lav_file) #ifdef USE_GDK_PIXBUF if(lav_file->format == 'x') return 0xffff; +#endif +#ifdef HAVE_LIBQUICKTIME + if(lav_file->format == 'q') + { + const char *compressor = quicktime_video_compressor(lav_file->qt_fd,0); + //@ prrff + if( (strncasecmp("mjpg", compressor, 4) == 0 || strncasecmp("jpeg", compressor, 4) == 0) || + strncasecmp("mjpa", compressor, 4) == 0) { + return CODEC_ID_MJPEG; + } else if( (strncasecmp("dvsd", compressor, 4) == 0) || strncasecmp("dv", compressor,2) == 0 ) { + return CODEC_ID_DVVIDEO; + } else if( strncasecmp("mp4v",compressor,4) == 0) { + return CODEC_ID_MPEG4; + } else if( strncasecmp("div3", compressor,4) == 0) { + return CODEC_ID_MSMPEG4V3; + } else if( strncasecmp("iyuv", compressor,4) == 0 || strncasecmp( "i420",compressor,4)==0) { + return 999; + } else if( strncasecmp("yv16", compressor,4) == 0) { + return 999; + } else if (strncasecmp("svq1",compressor,4) == 0 ) { + return CODEC_ID_SVQ1; + } else if (strncasecmp("rpza", compressor,4) == 0 ) { + return CODEC_ID_RPZA; + } + else + return -1; + + + } + // return quicktime_video_compressor(lav_file->qt_fd,0); #endif return AVI_video_compressor_type( lav_file->avi_fd ); } @@ -565,6 +850,10 @@ const char *lav_video_compressor(lav_file_t *lav_file) const char *tmp = (const char*) strdup("PICT"); return tmp; } +#endif +#ifdef HAVE_LIBQUICKTIME + if(lav_file->format == 'q') + return quicktime_video_compressor(lav_file->qt_fd,0); #endif return AVI_video_compressor(lav_file->avi_fd); } @@ -580,6 +869,10 @@ int lav_audio_channels(lav_file_t *lav_file) #ifdef USE_GDK_PIXBUF if(video_format == 'x') return 0; +#endif +#ifdef HAVE_LIBQUICKTIME + if(video_format == 'q') + return quicktime_track_channels(lav_file->qt_fd,0); #endif return AVI_audio_channels(lav_file->avi_fd); } @@ -596,6 +889,10 @@ int lav_audio_bits(lav_file_t *lav_file) if(video_format == 'x' ) return 0; #endif +#ifdef HAVE_LIBQUICKTIME + if(video_format == 'q') + return quicktime_audio_bits(lav_file->qt_fd,0); +#endif return (AVI_audio_bits(lav_file->avi_fd)); } @@ -611,6 +908,10 @@ long lav_audio_rate(lav_file_t *lav_file) if(video_format == 'x') return 0; #endif +#ifdef HAVE_LIBQUICKTIME + if( video_format == 'q') + return quicktime_sample_rate(lav_file->qt_fd,0); +#endif return (AVI_audio_rate(lav_file->avi_fd)); } @@ -626,6 +927,10 @@ long lav_audio_clips(lav_file_t *lav_file) if(video_format == 'x') return 0; #endif +#ifdef HAVE_LIBQUICKTIME + if(video_format == 'q') + return quicktime_audio_length(lav_file->qt_fd,0); +#endif return (AVI_audio_bytes(lav_file->avi_fd)/lav_file->bps); } @@ -640,6 +945,10 @@ long lav_frame_size(lav_file_t *lav_file, long frame) if(video_format == 'x') return 1; #endif +#ifdef HAVE_LIBQUICKTIME + if( video_format == 'q') + return quicktime_frame_size(lav_file->qt_fd,frame,0); +#endif return (AVI_frame_size(lav_file->avi_fd,frame)); } @@ -653,6 +962,9 @@ int lav_seek_start(lav_file_t *lav_file) #ifdef USE_GDK_PIXBUF if(video_format == 'x') return 1; +#endif +#ifdef HAVE_LIBQUICKTIME + return quicktime_seek_start(lav_file->qt_fd); #endif return (AVI_seek_start(lav_file->avi_fd)); } @@ -668,6 +980,10 @@ int lav_set_video_position(lav_file_t *lav_file, long frame) if(video_format == 'x') return 1; #endif +#ifdef HAVE_LIBQUICKTIME + if(video_format == 'q') + return quicktime_set_video_position(lav_file->qt_fd,frame,0); +#endif return (AVI_set_video_position(lav_file->avi_fd,frame)); } @@ -684,6 +1000,10 @@ int lav_read_frame(lav_file_t *lav_file, uint8_t *vidbuf) if(lav_file->format == 'x') return -1; #endif +#ifdef HAVE_LIBQUICKTIME + if(lav_file->format == 'q') + return quicktime_read_frame(lav_file->qt_fd,vidbuf,0); +#endif return (AVI_read_frame(lav_file->avi_fd,vidbuf)); } @@ -721,12 +1041,17 @@ int lav_set_audio_position(lav_file_t *lav_file, long clip) #ifdef USE_GDK_PIXBUF if(video_format == 'x') return 0; +#endif +#ifdef HAVE_LIBQUICKTIME + if(video_format =='q') + quicktime_set_audio_position(lav_file->qt_fd,clip,0); #endif return (AVI_set_audio_position(lav_file->avi_fd,clip*lav_file->bps)); } long lav_read_audio(lav_file_t *lav_file, uint8_t *audbuf, long samps) { + if(!lav_file->has_audio) { internal_error = ERROR_NOAUDIO; @@ -741,6 +1066,53 @@ long lav_read_audio(lav_file_t *lav_file, uint8_t *audbuf, long samps) return 0; #endif video_format = lav_file->format; internal_error = 0; /* for error messages */ +#ifdef HAVE_LIBQUICKTIME + if( video_format == 'q') + { + int64_t last_pos, start_pos; + int res, i, j; + int16_t *qt_audio = (int16_t *)audbuf, **qt_audion; + int channels = lav_audio_channels(lav_file); + uint8_t b0, b1; + qt_audion = malloc(channels * sizeof (int16_t **)); + for (i = 0; i < channels; i++) + qt_audion[i] = (int16_t *)malloc(samps * lav_file->bps); + + start_pos = quicktime_audio_position(lav_file->qt_fd, 0); + lqt_decode_audio_track(lav_file->qt_fd, qt_audion, NULL, samps, 0); + last_pos = lqt_last_audio_position(lav_file->qt_fd, 0); + res = last_pos - start_pos; + if (res <= 0) + goto out; + /* Interleave the channels of audio into the one buffer provided */ + for (i =0; i < res; i++) + { + for (j = 0; j < channels; j++) + qt_audio[(channels*i) + j] = qt_audion[j][i]; + } + + if (lav_detect_endian()) + { + i= 0; + while (i < (2*res) ) + { + b0 = 0; + b1 = 0; + b0 = (qt_audio[i] & 0x00FF); + b1 = (qt_audio[i] & 0xFF00) >> 8; + qt_audio[i] = (b0 <<8) + b1; + i = i +1; + } + } +out: + for (j = 0; j < channels; j++) + free(qt_audion[j]); + free(qt_audion); + return(res); + + + } +#endif return (AVI_read_audio(lav_file->avi_fd,audbuf,samps*lav_file->bps)/lav_file->bps); } @@ -764,6 +1136,9 @@ lav_file_t *lav_open_input_file(char *filename, int mmap_size) /* Set lav_fd */ +#ifdef HAVE_LIBQUICKTIME + char *audio_comp; +#endif lav_fd->avi_fd = 0; #ifdef SUPPORT_READ_DV2 lav_fd->dv_fd = 0; @@ -799,14 +1174,13 @@ lav_file_t *lav_open_input_file(char *filename, int mmap_size) lav_fd->avi_fd = AVI_open_input_file(filename,1,mmap_size); - video_format = 'a'; /* for error messages */ // if(!lav_fd->avi_fd) { if(lav_fd) free(lav_fd); return 0;} - if(lav_fd->avi_fd==NULL && AVI_errno == AVI_ERR_EMPTY ) + /* if(lav_fd->avi_fd==NULL && AVI_errno == AVI_ERR_EMPTY ) { if(lav_fd) free(lav_fd); return NULL; - } + }*/ if(lav_fd->avi_fd) { @@ -821,43 +1195,114 @@ lav_file_t *lav_open_input_file(char *filename, int mmap_size) else if( AVI_errno==AVI_ERR_NO_AVI ) { int ret = 0; -#ifdef USE_GDK_PIXBUF - lav_fd->picture = vj_picture_open( (const char*) filename, - output_scale_width, output_scale_height, output_yuv ); - if(lav_fd->picture) + int alt = 0; +#ifdef HAVE_LIBQUICKTIME + if(quicktime_check_sig(filename)) { - lav_fd->format = 'x'; - lav_fd->has_audio = 0; - video_comp = strdup( "PICT" ); - ret = 1; + quicktime_pasp_t pasp; + int nfields, detail; + lav_fd->qt_fd = quicktime_open(filename,1,0); + video_format = 'q'; /* for error messages */ + if (!lav_fd->qt_fd) + { + veejay_msg(VEEJAY_MSG_ERROR, "Unable to open quicktime file"); + free(lav_fd); + return 0; + } + lav_fd->avi_fd = NULL; + lav_fd->format = 'q'; + video_comp = quicktime_video_compressor(lav_fd->qt_fd,0); + + /* We want at least one video track */ + if (quicktime_video_tracks(lav_fd->qt_fd) < 1) + { + veejay_msg(VEEJAY_MSG_ERROR, "At least one video track required"); + lav_close(lav_fd); + internal_error = ERROR_FORMAT; + return 0; + } + /* + * If the quicktime file has the sample aspect atom then use it to set + * the sar values in the lav_fd structure. Hardwired (like everywhere else) + * to only look at track 0. + */ + + if (lqt_get_pasp(lav_fd->qt_fd, 0, &pasp) != 0) + { + lav_fd->sar_w = pasp.hSpacing; + lav_fd->sar_h = pasp.vSpacing; + } + /* + * If a 'fiel' atom is present (not guaranteed) then use it to set the + * interlacing type. + */ + + if (lqt_get_fiel(lav_fd->qt_fd, 0, &nfields, &detail) != 0) + { + if (nfields == 2) + { + if (detail == 14 || detail == 6) + lav_fd->interlacing = LAV_INTER_BOTTOM_FIRST; + else if (detail == 9 || detail == 1) + lav_fd->interlacing = LAV_INTER_TOP_FIRST; + else + mjpeg_warn("unknown 'detail' in 'fiel' atom: %d", detail); + } + else + lav_fd->interlacing = LAV_NOT_INTERLACED; + } + /* Check for audio tracks */ + lav_fd->has_audio = 0; + if (quicktime_audio_tracks(lav_fd->qt_fd)) + { + audio_comp = quicktime_audio_compressor(lav_fd->qt_fd,0); + if (strncasecmp(audio_comp, QUICKTIME_TWOS,4)==0) + lav_fd->has_audio = 1; + } + alt = 1; + ret = 1; } - else +#endif +#ifdef USE_GDK_PIXBUF + if(!alt) { + lav_fd->picture = vj_picture_open( (const char*) filename, + output_scale_width, output_scale_height, output_yuv ); + if(lav_fd->picture) + { + lav_fd->format = 'x'; + lav_fd->has_audio = 0; + video_comp = strdup( "PICT" ); + ret = 1; + alt = 1; + } + } #endif #ifdef SUPPORT_READ_DV2 - ret = 0; - lav_fd->dv_fd = rawdv_open_input_file(filename,mmap_size); - if(lav_fd->dv_fd > 0) + if(!alt) { - lav_fd->MJPG_chroma = rawdv_sampling( lav_fd->dv_fd ); - if ( lav_fd->MJPG_chroma == -1 ) + ret = 0; + lav_fd->dv_fd = rawdv_open_input_file(filename,mmap_size); + if(lav_fd->dv_fd > 0) { - veejay_msg(VEEJAY_MSG_ERROR, "Dont know how to treat this file"); - ret = 0; - } - else - { - video_comp = rawdv_video_compressor( lav_fd->dv_fd ); - lav_fd->format = 'b'; - lav_fd->has_audio = 0; - ret = 1; - } - } -#endif -#ifdef USE_GDK_PIXBUF + lav_fd->MJPG_chroma = rawdv_sampling( lav_fd->dv_fd ); + if ( lav_fd->MJPG_chroma == -1 ) + { + veejay_msg(VEEJAY_MSG_ERROR, "Dont know how to treat this file"); + ret = 0; + } + else + { + video_comp = rawdv_video_compressor( lav_fd->dv_fd ); + lav_fd->format = 'b'; + lav_fd->has_audio = 0; + ret = 1; + veejay_msg(VEEJAY_MSG_DEBUG, "RAW DV file"); + } + } } -#endif +#endif if(ret == 0 || video_comp == NULL) { free(lav_fd); @@ -868,9 +1313,12 @@ lav_file_t *lav_open_input_file(char *filename, int mmap_size) } + veejay_msg(0, "AVI_errno = %d", AVI_errno ); + lav_fd->bps = (lav_audio_channels(lav_fd)*lav_audio_bits(lav_fd)+7)/8; if(lav_fd->bps==0) lav_fd->bps=1; /* make it save since we will divide by that value */ + #ifdef USE_GDK_PIXBUF if(strncasecmp(video_comp, "PICT",4) == 0 ) { @@ -880,7 +1328,39 @@ lav_file_t *lav_open_input_file(char *filename, int mmap_size) return lav_fd; } #endif - if(strncasecmp(video_comp, "div3",4)==0) { + +#ifdef HAVE_LIBQUICKTIME + if( lav_fd->qt_fd ) + { + /* if(strncasecmp( video_comp, "svq1", 4 ) == 0 ) + { + + lav_fd->MJPG_chroma = CHROMA422; + return lav_fd; + }*/ + + int cmodel = lqt_get_cmodel( lav_fd->qt_fd,0 ); + veejay_msg( VEEJAY_MSG_DEBUG, "Colormodel is %s", + lqt_colormodel_to_string(cmodel) ); + if(cmodel == BC_YUV420P ) + lav_fd->MJPG_chroma = CHROMA420; + else if(cmodel == BC_YUV422P ) + lav_fd->MJPG_chroma = CHROMA422; + else if(cmodel == BC_RGB888 ) { + lav_fd->MJPG_chroma = CHROMA422; + } + else + { + veejay_msg(VEEJAY_MSG_ERROR, "Unsupported color model %s", + lqt_colormodel_to_string( cmodel )); + return NULL; + } + return lav_fd; + } +#endif + + if(strncasecmp(video_comp, "div3",4)==0) + { lav_fd->MJPG_chroma = CHROMA420; lav_fd->format = 'D'; lav_fd->interlacing = LAV_NOT_INTERLACED; @@ -914,8 +1394,6 @@ lav_file_t *lav_open_input_file(char *filename, int mmap_size) } if (strncasecmp(video_comp,"dvsd",4)==0 || strncasecmp(video_comp,"dv",2)==0) { - //veejay_msg(VEEJAY_MSG_DEBUG,"!! Guessing sampling type"); - // lav_fd->MJPG_chroma = CHROMA422; int gw = lav_video_height( lav_fd ); if( gw == 480 ) lav_fd->MJPG_chroma = CHROMA411; @@ -1059,7 +1537,7 @@ lav_file_t *lav_open_input_file(char *filename, int mmap_size) } ierr = ERROR_FORMAT; - + veejay_msg(VEEJAY_MSG_ERROR, "Unrecognized format '%s'", video_comp); ERREXIT: lav_close(lav_fd); @@ -1202,6 +1680,11 @@ int lav_fileno(lav_file_t *lav_file) case 'M': res = AVI_fileno( lav_file->avi_fd ); break; +#ifdef HAVE_LIBQUICKTIME + case 'q': + res = lqt_fileno((quicktime_t *)lav_file->qt_fd); + break; +#endif default: res = -1; } @@ -1209,6 +1692,40 @@ int lav_fileno(lav_file_t *lav_file) return res; } +/* We need this to reorder the 32 bit values for big endian systems */ +uint32_t reorder_32(uint32_t todo, int big_endian) +{ + unsigned char b0, b1, b2, b3; + unsigned long reversed; + + if( big_endian ) + { + b0 = (todo & 0x000000FF); + b1 = (todo & 0x0000FF00) >> 8; + b2 = (todo & 0x00FF0000) >> 16; + b3 = (todo & 0xFF000000) >> 24; + + reversed = (b0 << 24) + (b1 << 16) + (b2 << 8) +b3; + return reversed; + } + return todo; +} +int lav_detect_endian (void) +{ + unsigned int fred; + char *pfred; + + fred = 2 | (1 << (sizeof(int)*8-8)); + pfred = (char *)&fred; + + if (*pfred == 1) + return 1; + else if(*pfred == 2) + return 0; + else + return -1; +} + @@ -1221,4 +1738,3 @@ int lav_fileno(lav_file_t *lav_file) - diff --git a/veejay-current/libel/lav_io.h b/veejay-current/libel/lav_io.h index 1866d18d..3a03de59 100644 --- a/veejay-current/libel/lav_io.h +++ b/veejay-current/libel/lav_io.h @@ -65,6 +65,7 @@ typedef struct #ifdef SUPPORT_READ_DV2 dv_t *dv_fd; #endif + void *qt_fd; int jpeg_fd; char *jpeg_filename; #ifdef USE_GDK_PIXBUF diff --git a/veejay-current/libel/vj-el.c b/veejay-current/libel/vj-el.c index 2615c438..14cc44ea 100644 --- a/veejay-current/libel/vj-el.c +++ b/veejay-current/libel/vj-el.c @@ -49,7 +49,7 @@ #include "rawdv.h" #include "vj-dv.h" #endif -#define MAX_CODECS 12 +#define MAX_CODECS 32 #define CODEC_ID_YUV420 999 #define CODEC_ID_YUV422 998 @@ -94,6 +94,8 @@ static struct { "divx" ,CODEC_ID_MSMPEG4V3 }, { "i420", CODEC_ID_YUV420 }, { "i422", CODEC_ID_YUV422 }, + { "svq1", CODEC_ID_SVQ1 }, + { "rpza", CODEC_ID_RPZA }, { NULL , 0 }, }; @@ -130,6 +132,8 @@ static struct { "pict", 0xffff }, /* invalid fourcc */ { "hfyu", CODEC_ID_HUFFYUV}, { "cyuv", CODEC_ID_CYUV }, + { "svq1", CODEC_ID_SVQ1 }, + { "rpza", CODEC_ID_RPZA }, #if LIBAVCODEC_BUILD > 4680 { "spsx", CODEC_ID_SP5X }, #endif @@ -164,7 +168,9 @@ static _el_get_codec(int id ) for( i = 0; _supported_codecs[i].name != NULL ; i ++ ) { if( _supported_codecs[i].id == id ) + { return i; + } } return -1; } @@ -300,6 +306,10 @@ vj_decoder *_el_new_decoder( int id , int width, int height, float fps, int pixe if(!d) return NULL; memset( d, 0, sizeof(vj_decoder)); + + veejay_msg(VEEJAY_MSG_DEBUG, "\tCodec %x (%d) , %d x %d at %f, in=%d, out=%d", + id,id,width,height,fps,pixel_format,out_fmt); + #ifdef SUPPORT_READ_DV2 if( id != CODEC_ID_YUV422 && id != CODEC_ID_YUV420 && id != CODEC_ID_DVVIDEO) { @@ -371,8 +381,6 @@ vj_decoder *_el_new_decoder( int id , int width, int height, float fps, int pixe #endif } - - d->tmp_buffer = (uint8_t*) vj_malloc(sizeof(uint8_t) * width * height * 4 ); if(!d->tmp_buffer) { @@ -424,18 +432,7 @@ int open_video_file(char *filename, editlist * el, int preserve_pathname, int de //@@ should identify sampling format, 411,420,444 static int _el_probe_for_pixel_fmt( lav_file_t *fd ) { - switch( fd->MJPG_chroma ) - { - case CHROMA411: - return FMT_411; - case CHROMA420: - return FMT_420; - case CHROMA422: - return FMT_422; - case CHROMA444: - return FMT_444; - } - return FMT_444; + return lav_video_cmodel( fd ); } int open_video_file(char *filename, editlist * el, int preserve_pathname, int deinter, int force, char override_norm) @@ -532,7 +529,6 @@ int open_video_file(char *filename, editlist * el, int preserve_pathname, int de } el->yuv_taste[n] = pix_fmt; -veejay_msg(VEEJAY_MSG_DEBUG, "%s : %d", __FUNCTION__, pix_fmt ); if(lav_video_frames(el->lav_fd[n]) < 2) { @@ -732,10 +728,9 @@ veejay_msg(VEEJAY_MSG_DEBUG, "%s : %d", __FUNCTION__, pix_fmt ); if(el->video_file_list[n]) free(el->video_file_list[n]); return -1; } - + veejay_msg(0, "video compressor %s", compr_type ); // initialze a decoder if needed decoder_id = _el_get_codec_id( compr_type ); - if(decoder_id > 0 && decoder_id != 0xffff) { int c_i = _el_get_codec(decoder_id); @@ -759,10 +754,14 @@ veejay_msg(VEEJAY_MSG_DEBUG, "%s : %d", __FUNCTION__, pix_fmt ); if( el->video_file_list[n]) free(el->video_file_list[n]); return -1; } + else + { + veejay_msg(VEEJAY_MSG_INFO, "\tDecoder %s initialized in slot %d", compr_type, c_i); + } } } - if(decoder_id == 0) + if(decoder_id <= 0) { veejay_msg(VEEJAY_MSG_ERROR, "Dont know how to handle %s (fmt %d) %x", compr_type, pix_fmt,decoder_id); if(realname) free(realname); @@ -880,22 +879,28 @@ int vj_el_get_video_frame(editlist *el, long nframe, uint8_t *dst[3]) { veejay_msg(VEEJAY_MSG_ERROR,"Error setting video position: %s", lav_strerror()); + return -1; } } c_i = _el_get_codec( decoder_id ); - if(c_i >= 0 && c_i < MAX_CODECS) + if(c_i >= 0 && c_i < MAX_CODECS && el_codecs[c_i] != NULL) d = el_codecs[c_i]; else { - veejay_msg(VEEJAY_MSG_ERROR, "Choked on decoder" ); + veejay_msg(VEEJAY_MSG_ERROR, "Choked on decoder %x (%d), slot %d",decoder_id,decoder_id, c_i ); return -1; } if(!in_cache ) { + if( d == NULL ) + { + veejay_msg(VEEJAY_MSG_ERROR, "Codec not initlaized"); + return -1; + } if(lav_filetype( el->lav_fd[N_EL_FILE(n)] ) != 'x') - { + { res = lav_read_frame(el->lav_fd[N_EL_FILE(n)], d->tmp_buffer); if(res > 0 && el->cache) cache_frame( el->cache, d->tmp_buffer, res, nframe, decoder_id ); @@ -982,10 +987,10 @@ int vj_el_get_video_frame(editlist *el, long nframe, uint8_t *dst[3]) data, res ); - if( len <= 0 ) + if( len <= 0 || !got_picture) { veejay_msg(VEEJAY_MSG_ERROR, - "Frame %ld broken, fix your videofiles", + "Frame %ld broken or video file is not made of pure I-frames, fix your videofiles", nframe); return 0; } @@ -995,6 +1000,8 @@ int vj_el_get_video_frame(editlist *el, long nframe, uint8_t *dst[3]) //@ sampling + int src_fmt = in_pix_fmt; + /* int src_fmt = PIX_FMT_YUV444P; // int src_fmt = ( in_pix_fmt == FMT_420 ? PIX_FMT_YUV420P: PIX_FMT_YUV422P ); switch(in_pix_fmt) @@ -1002,10 +1009,9 @@ int vj_el_get_video_frame(editlist *el, long nframe, uint8_t *dst[3]) case FMT_420: src_fmt = PIX_FMT_YUV420P; break; case FMT_411: src_fmt = PIX_FMT_YUV411P; break; case FMT_422: src_fmt = PIX_FMT_YUV422P; break; - } + }*/ int dst_fmt = ( out_pix_fmt== FMT_420 ? PIX_FMT_YUV420P: PIX_FMT_YUV422P) ; - pict.data[0] = dst[0]; pict.data[1] = dst[1]; pict.data[2] = dst[2]; @@ -1014,6 +1020,7 @@ int vj_el_get_video_frame(editlist *el, long nframe, uint8_t *dst[3]) pict.linesize[1] = el->video_width / 2; pict.linesize[2] = el->video_width / 2; + if(!d->frame->opaque) { if( el->auto_deinter && inter != LAV_NOT_INTERLACED) @@ -1023,7 +1030,6 @@ int vj_el_get_video_frame(editlist *el, long nframe, uint8_t *dst[3]) pict2.data[2] = d->deinterlace_buffer[2]; pict2.linesize[1] = el->video_width >> 1; pict2.linesize[2] = el->video_width >> 1; - pict2.linesize[0] = el->video_width; avpicture_deinterlace( &pict2, @@ -1043,10 +1049,7 @@ int vj_el_get_video_frame(editlist *el, long nframe, uint8_t *dst[3]) } else { - //VJFrame *dst = d->frame->opaque; - - dst[0] = - d->frame->data[0]; + dst[0] = d->frame->data[0]; dst[1] = d->frame->data[1]; dst[2] = d->frame->data[2]; } @@ -1099,13 +1102,17 @@ int vj_el_get_audio_frame(editlist *el, uint32_t nframe, uint8_t *dst) ret = lav_set_audio_position(el->lav_fd[N_EL_FILE(n)], ns0); if (ret < 0) + { + veejay_msg(0,"Unable to seek to frame position %ld", ns0); return -1; - + } //mlt need int16_t ret = lav_read_audio(el->lav_fd[N_EL_FILE(n)], dst, (ns1 - ns0)); if (ret < 0) + { + veejay_msg(0,"Unable to read audio data"); return -1; - + } return (ns1 - ns0); } diff --git a/veejay-current/veejay/Makefile.am b/veejay-current/veejay/Makefile.am index 978d7539..2ad51337 100644 --- a/veejay-current/veejay/Makefile.am +++ b/veejay-current/veejay/Makefile.am @@ -16,7 +16,7 @@ INCLUDES = -I$(top_srcdir) -I$(includedir) \ -I$(top_srcdir)/liblavjpeg \ -I$(top_srcdir)/libsamplerec \ -I$(top_srcdir)/libvevo \ - $(FFMPEG_AVCODEC_CFLAGS) $(FFMPEG_AVFORMAT_CFLAGS)\ + $(FFMPEG_AVCODEC_CFLAGS) $(FFMPEG_AVFORMAT_CFLAGS) $(LIBQUICKTIME_CFLAGS) \ $(AVIPLAY_CFLAGS) ${XML_CFLAGS} ${GTK_CFLAGS} ${DV_FLAGS} ${X_CFLAGS} ${XML_CPPFLAGS} \ $(DIRECTFB_CFLAGS) ${SDL_CFLAGS} ${JPEG_CFLAGS} ${PTHREAD_CFLAGS} ${SAMPLERATE_CFLAGS} ${MJPEGTOOLS_CFLAGS} @@ -58,7 +58,7 @@ libveejay_la_LIBADD = -L$(top_builddir)/libOSC / -lOSC \ libveejay_la_LDFLAGS += ${SDL_LIBS} ${DIRECTFB_LIBS} ${PTHREAD_LIBS} \ ${XML_LIBS} ${JPEG_LIBS} ${JACK_LIBS} \ ${FFMPEG_AVFORMAT_LIBS} ${FFMPEG_AVCODEC_LIBS} \ - ${LIBDV_LIBS} ${LIBM_LIBS} ${PIXBUF_LIBS} ${MJPEGTOOLS_LIBS}\ + ${LIBDV_LIBS} ${LIBM_LIBS} ${PIXBUF_LIBS} ${MJPEGTOOLS_LIBS} ${LIBQUICKTIME_LIBS} \ -DDYNAMIC -O3 -Wall -rdynamic diff --git a/veejay-current/veejay/vj-perform.c b/veejay-current/veejay/vj-perform.c index 04a22035..62906759 100644 --- a/veejay-current/veejay/vj-perform.c +++ b/veejay-current/veejay/vj-perform.c @@ -2165,6 +2165,7 @@ void vj_perform_plain_fill_buffer(veejay_t * info, int entry, int skip) if(ret <= 0) { + veejay_msg(0, "getting video frame. Stop veejay"); veejay_change_state(info, LAVPLAY_STATE_STOP); } }