diff --git a/veejay-ng/config.h.in b/veejay-ng/config.h.in deleted file mode 100644 index d1a55108..00000000 --- a/veejay-ng/config.h.in +++ /dev/null @@ -1,271 +0,0 @@ -/* config.h.in. Generated from configure.ac by autoheader. */ - -/* Compiling for MIPS CPU */ -#undef ARCH_MIPS - -/* Compiling for PowerPC */ -#undef ARCH_PPC - -/* Compiling for x86 architecture */ -#undef ARCH_X86 - -/* Compiling for x86-64 architecture CPU */ -#undef ARCH_X86_64 - -/* Define to 1 if you have the header file. */ -#undef HAVE_ALLOCA_H - -/* Inline PPC Altivec primitives available */ -#undef HAVE_ALTIVEC - -/* Compiling in 3Dnow */ -#undef HAVE_ASM_3DNOW - -/* Compiling in MMX support */ -#undef HAVE_ASM_MMX - -/* Compiling in MMX2 */ -#undef HAVE_ASM_MMX2 - -/* Compiling with nasm */ -#undef HAVE_ASM_NASM - -/* Compiling in SSE support */ -#undef HAVE_ASM_SSE - -/* Compiling in SSE2 support */ -#undef HAVE_ASM_SSE2 - -/* use avcodec */ -#undef HAVE_AVCODEC - -/* use avformat */ -#undef HAVE_AVFORMAT - -/* Define to 1 if you have the `bzero' function. */ -#undef HAVE_BZERO - -/* Compiling in CMOV */ -#undef HAVE_CMOV - -/* MAC OS X Darin */ -#undef HAVE_DARWIN - -/* Define to 1 if you have the header file. */ -#undef HAVE_DLFCN_H - -/* Compile with dlopen support */ -#undef HAVE_DL_DLOPEN - -/* Define to 1 if you have the header file. */ -#undef HAVE_FENV_H - -/* long getopt support */ -#undef HAVE_GETOPT_LONG - -/* Define to 1 if you have the `getpagesize' function. */ -#undef HAVE_GETPAGESIZE - -/* Define to 1 if you have the `gettimeofday' function. */ -#undef HAVE_GETTIMEOFDAY - -/* Glib library present */ -#undef HAVE_GLIB - -/* Define to 1 if you have the header file. */ -#undef HAVE_GL_GLUT_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_GL_GL_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_INTTYPES_H - -/* Compiling with support for Jack */ -#undef HAVE_JACK - -/* Define to 1 if you have the `dl' library (-ldl). */ -#undef HAVE_LIBDL - -/* liblo installed */ -#undef HAVE_LIBLO - -/* Compiling with pthread library */ -#undef HAVE_LIBPTHREAD - -/* libxf86dga is present */ -#undef HAVE_LIBXXF86DGA - -/* Linux platform */ -#undef HAVE_LINUX - -/* Define to 1 if you have the `memalign' function. */ -#undef HAVE_MEMALIGN - -/* Define to 1 if you have the `memcpy' function. */ -#undef HAVE_MEMCPY - -/* Define to 1 if you have the header file. */ -#undef HAVE_MEMORY_H - -/* Define to 1 if you have the `memset' function. */ -#undef HAVE_MEMSET - -/* Compiling for MIPS CPU */ -#undef HAVE_MIPS - -/* MJPEGTools installed */ -#undef HAVE_MJPEGTOOLS - -/* Define to 1 if you have the `mmap' function. */ -#undef HAVE_MMAP - -/* Compiling in MMX support in ffmpeg */ -#undef HAVE_MMX - -/* Compiling in MMX2 */ -#undef HAVE_MMX2 - -/* Define to 1 if you have the `posix_memalign' function. */ -#undef HAVE_POSIX_MEMALIGN - -/* Define to 1 if you have the `pow' function. */ -#undef HAVE_POW - -/* Compiling for PowerPC CPU */ -#undef HAVE_PPCCPU - -/* Compile for playstation2 */ -#undef HAVE_PS2 - -/* Using pthread stack size */ -#undef HAVE_PTHREADSTACKSIZE - -/* Set to 1 if you have libsamplerate. */ -#undef HAVE_SAMPLERATE - -/* Define to 1 if you have the `sched_get_priority_max' function. */ -#undef HAVE_SCHED_GET_PRIORITY_MAX - -/* SDL library present */ -#undef HAVE_SDL - -/* Define to 1 if you have the `select' function. */ -#undef HAVE_SELECT - -/* Define to 1 if you have the `socket' function. */ -#undef HAVE_SOCKET - -/* Compiling in SSE support */ -#undef HAVE_SSE - -/* Compiling in SSE2 support */ -#undef HAVE_SSE2 - -/* Define to 1 if you have the header file. */ -#undef HAVE_STDINT_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_STDLIB_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_STRINGS_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_STRING_H - -/* Define to 1 if you have the `strncasecmp' function. */ -#undef HAVE_STRNCASECMP - -/* Define to 1 if you have the `strndup' function. */ -#undef HAVE_STRNDUP - -/* Define to 1 if you have the `strstr' function. */ -#undef HAVE_STRSTR - -/* Define to 1 if you have the header file. */ -#undef HAVE_SYS_STAT_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_SYS_TYPES_H - -/* Set to 1 if you have unicap. */ -#undef HAVE_UNICAP - -/* Define to 1 if you have the header file. */ -#undef HAVE_UNISTD_H - -/* Building for Linux - using the video4linux API */ -#undef HAVE_V4L - -/* Compiling for x86 architecture CPU */ -#undef HAVE_X86CPU - -/* Compiling for x86-64 architecture CPU */ -#undef HAVE_X86_CPU - -/* Compiling with XML2 */ -#undef HAVE_XML2 - -/* Is __progname defined by system? */ -#undef HAVE___PROGNAME - -/* Name of package */ -#undef PACKAGE - -/* Define to the address where bug reports for this package should be sent. */ -#undef PACKAGE_BUGREPORT - -/* Define to the full name of this package. */ -#undef PACKAGE_NAME - -/* Define to the full name and version of this package. */ -#undef PACKAGE_STRING - -/* Define to the one symbol short name of this package. */ -#undef PACKAGE_TARNAME - -/* Define to the version of this package. */ -#undef PACKAGE_VERSION - -/* Define as the return type of signal handlers (`int' or `void'). */ -#undef RETSIGTYPE - -/* Define to 1 if you have the ANSI C header files. */ -#undef STDC_HEADERS - -/* libdv is present */ -#undef SUPPORT_READ_DV2 - -/* Compiling in a video output X screen */ -#undef USE_DISPLAY - -/* Building veejay */ -#undef VEEJAY - -/* Version number of package */ -#undef VERSION - -/* Define to 1 if your processor stores words with the most significant byte - first (like Motorola and SPARC, unlike Intel and VAX). */ -#undef WORDS_BIGENDIAN - -/* Number of bits in a file offset, on hosts where this is settable. */ -#undef _FILE_OFFSET_BITS - -/* Enable GNU extensions on systems that have them. */ -#ifndef _GNU_SOURCE -# undef _GNU_SOURCE -#endif - -/* Define for large files, on AIX-style hosts. */ -#undef _LARGE_FILES - -/* Define to empty if `const' does not conform to ANSI C. */ -#undef const - -/* Define to `__inline__' or `__inline' if that's what the C compiler - calls it, or to nothing if 'inline' is not supported under any name. */ -#ifndef __cplusplus -#undef inline -#endif diff --git a/veejay-ng/configure.ac b/veejay-ng/configure.ac index 3d1c1fdc..efd6267d 100644 --- a/veejay-ng/configure.ac +++ b/veejay-ng/configure.ac @@ -281,6 +281,22 @@ if test x$with_libdv != xno ; then [have_libdv=false]) fi +dnl ********************************************************************* +dnl Check for quicktime +dnl (creates LIBQUICKTIME_CFLAGS, LIBQUICKTIME_LIBS; defines HAVE_LIBQUICKTIME) +dnl ********************************************************************* + +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 ********************************************************************* dnl Check for mjpegtools dnl (creates MJPEGYTOOLS_CFLAGS, @@ -866,6 +882,7 @@ AC_MSG_NOTICE([]) AC_MSG_NOTICE([ Required dependencies:]) AC_MSG_NOTICE([ - POSIX Threads (pthread) : ${have_pthread}]) AC_MSG_NOTICE([ - MJPEGTools : ${have_mjpegtools}]) +AC_MSG_NOTICE([ - QuickTime support : ${have_libquicktime} ]) AC_MSG_NOTICE([ - SDL Video : ${have_sdl}]) AC_MSG_NOTICE([ - Leightweight OSC : ${have_liblo}]) AC_MSG_NOTICE([ Optional dependencies]) diff --git a/veejay-ng/libel/Makefile.am b/veejay-ng/libel/Makefile.am index f7751f31..07e09cea 100644 --- a/veejay-ng/libel/Makefile.am +++ b/veejay-ng/libel/Makefile.am @@ -4,7 +4,7 @@ MAINTAINERCLEANFILES = Makefile.in INCLUDES = -I$(top_srcdir) -I$(includedir) -I$(top_srcdir)/vjmem \ -I$(top_srcdir)/vjmsg \ - $(MJPEGTOOLS_CFLAGS) ${FFMPEG_CFLAGS} + $(MJPEGTOOLS_CFLAGS) ${FFMPEG_CFLAGS} ${LIBQUICKTIME_CFLAGS} VJEL_LIB_FILE = libel.la noinst_LTLIBRARIES = $(VJEL_LIB_FILE) diff --git a/veejay-ng/libel/avilib.c b/veejay-ng/libel/avilib.c index e7bb44b7..eb982654 100644 --- a/veejay-ng/libel/avilib.c +++ b/veejay-ng/libel/avilib.c @@ -1,45 +1,44 @@ /* - * Some utilities for writing and reading AVI files. - * These are not intended to serve for a full blown - * AVI handling software (this would be much too complex) - * The only intention is to write out MJPEG encoded - * AVIs with sound and to be able to read them back again. - * These utilities should work with other types of codecs too, however. + * avilib.c * - * Copyright (C) 1999 Rainer Johanni + * Copyright (C) Thomas Östreich - June 2001 + * multiple audio track support Copyright (C) 2002 Thomas Östreich * - * This program is free software; you can redistribute it and/or modify + * Original code: + * Copyright (C) 1999 Rainer Johanni + * + * This file is part of transcode, a video stream processing tool + * + * transcode is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * transcode 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 General Public License for more details. - * + * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -/** \defgroup avilib AVI library for writing and reading AVI files + * along with GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. * */ #include -#include -#include #include -#include -#include -#include -#include -#include -#include + #include "avilib.h" -#include "mjpeg_logging.h" -#include + +#define INFO_LIST + +// add a new riff chunk after XX MB +//#define NEW_RIFF_THRES (1900*1024*1024) +#define NEW_RIFF_THRES (1900*1024*1024) +//#define NEW_RIFF_THRES (10*1024*1024) + +// Maximum number of indices per stream +#define NR_IXNN_CHUNKS 32 /* There is an experimental kernel patch available at * http://www.tech9.net/rml/linux/ * that adds the O_STREAMING flag for open(). Files opened this way will @@ -50,36 +49,84 @@ * * we leave it out if it's unknown, since its value differs per arch... */ + + #ifndef O_STREAMING #define O_STREAMING 0 #endif + +#define DEBUG_ODML +#undef DEBUG_ODML + /* The following variable indicates the kind of error */ long AVI_errno = 0; +#define MAX_INFO_STRLEN 64 +static char id_str[MAX_INFO_STRLEN]; + +#define FRAME_RATE_SCALE 1000000 + /******************************************************************* * * * Utilities for writing an AVI File * * * *******************************************************************/ -/* AVI_MAX_LEN: The maximum length of an AVI file, we stay a bit below - the 2GB limit (Remember: 2*10^9 is smaller than 2 GB) */ +static ssize_t avi_read(int fd, char *buf, size_t len) +{ + ssize_t n = 0; + ssize_t r = 0; -#define AVI_MAX_LEN 2000000000 + while (r < len) { + n = read (fd, buf + r, len - r); + if (n == 0) + break; + if (n < 0) { + if (errno == EINTR) + continue; + else + break; + } + + r += n; + } + + return r; +} + +static ssize_t avi_write (int fd, char *buf, size_t len) +{ + ssize_t n = 0; + ssize_t r = 0; + + while (r < len) { + n = write (fd, buf + r, len - r); + if (n < 0) + return n; + + r += n; + } + return r; +} /* HEADERBYTES: The number of bytes to reserve for the header */ #define HEADERBYTES 2048 +/* AVI_MAX_LEN: The maximum length of an AVI file, we stay a bit below + the 2GB limit (Remember: 2*10^9 is smaller than 2 GB) */ + +#define AVI_MAX_LEN (UINT_MAX-(1<<20)*16-HEADERBYTES) + #define PAD_EVEN(x) ( ((x)+1) & ~1 ) -/* Copy n into dst as a 4 byte, little endian number. +/* Copy n into dst as a 4 or 2 byte, little endian number. Should also work on big endian machines */ -static void long2str(uint8_t *dst, int n) +static void long2str(unsigned char *dst, int32_t n) { dst[0] = (n )&0xff; dst[1] = (n>> 8)&0xff; @@ -87,36 +134,69 @@ static void long2str(uint8_t *dst, int n) dst[3] = (n>>24)&0xff; } +#ifdef WORDS_BIGENDIAN +static void short2str(unsigned char *dst, int32_t n) +{ + dst[0] = (n )&0xff; + dst[1] = (n>> 8)&0xff; +} +#endif + /* Convert a string of 4 or 2 bytes to a number, also working on big endian machines */ -static unsigned long str2ulong(uint8_t *str) +static uint64_t str2ullong(unsigned char *str) +{ + uint64_t r = (str[0] | (str[1]<<8) | (str[2]<<16) | (str[3]<<24)); + uint64_t s = (str[4] | (str[5]<<8) | (str[6]<<16) | (str[7]<<24)); + return ((s<<32)&0xffffffff00000000ULL)|(r&0xffffffffULL); +} + +static uint32_t str2ulong(unsigned char *str) { return ( str[0] | (str[1]<<8) | (str[2]<<16) | (str[3]<<24) ); } -static unsigned long str2ushort(uint8_t *str) +static uint32_t str2ushort(unsigned char *str) { return ( str[0] | (str[1]<<8) ); } -/* Calculate audio clip size from number of bits and number of channels. +// bit 31 denotes a keyframe +static uint32_t str2ulong_len (unsigned char *str) +{ + return str2ulong(str) & 0x7fffffff; +} + + +// if bit 31 is 0, its a keyframe +static uint32_t str2ulong_key (unsigned char *str) +{ + uint32_t c = str2ulong(str); + c &= 0x80000000; + if (c == 0) return 0x10; + else return 0; +} + +/* Calculate audio sample size from number of bits and number of channels. This may have to be adjusted for eg. 12 bits and stereo */ -static int avi_sampsize(avi_t *AVI) +static int avi_sampsize(avi_t *AVI, int j) { int s; - s = ((AVI->a_bits+7)/8)*AVI->a_chans; - if(s==0) s=1; /* avoid possible zero divisions */ + s = ((AVI->track[j].a_bits+7)/8)*AVI->track[j].a_chans; + // if(s==0) s=1; /* avoid possible zero divisions */ + if(s<4) s=4; /* avoid possible zero divisions */ return s; } /* Add a chunk (=tag and data) to the AVI file, returns -1 on write error, 0 on success */ -static int avi_add_chunk(avi_t *AVI, const uint8_t *tag, uint8_t *data, int length) +static int avi_add_chunk(avi_t *AVI, unsigned char *tag, unsigned char *data, int length) { - uint8_t c[8]; - + unsigned char c[8]; + char p=0; + /* Copy tag and length int c, so that we need only 1 write system call for these two values */ @@ -126,10 +206,9 @@ static int avi_add_chunk(avi_t *AVI, const uint8_t *tag, uint8_t *data, int leng /* Output tag, length and data, restore previous position if the write fails */ - length = PAD_EVEN(length); - - if( write(AVI->fdes,c,8) != 8 || - write(AVI->fdes,data,length) != length ) + if( avi_write(AVI->fdes,(char *)c,8) != 8 || + avi_write(AVI->fdes,(char *)data,length) != length || + avi_write(AVI->fdes,&p,length&1) != (length&1)) // if len is uneven, write a pad byte { lseek(AVI->fdes,AVI->pos,SEEK_SET); AVI_errno = AVI_ERR_WRITE; @@ -138,41 +217,396 @@ static int avi_add_chunk(avi_t *AVI, const uint8_t *tag, uint8_t *data, int leng /* Update file position */ - AVI->pos += 8 + length; + AVI->pos += 8 + PAD_EVEN(length); + + //fprintf(stderr, "pos=%lu %s\n", AVI->pos, tag); return 0; } -static int avi_add_index_entry(avi_t *AVI, const uint8_t *tag, long flags, long pos, long len) +#define OUTD(n) long2str(ix00+bl,n); bl+=4 +#define OUTW(n) ix00[bl] = (n)&0xff; ix00[bl+1] = (n>>8)&0xff; bl+=2 +#define OUTC(n) ix00[bl] = (n)&0xff; bl+=1 +#define OUTS(s) memcpy(ix00+bl,s,4); bl+=4 + +// this does the physical writeout of the ix## structure +static int avi_ixnn_entry(avi_t *AVI, avistdindex_chunk *ch, avisuperindex_entry *en) +{ + int bl, k; + unsigned int max = ch->nEntriesInUse * sizeof (uint32_t) * ch->wLongsPerEntry + 24; // header + char *ix00 = malloc (max); + char dfcc[5]; + memcpy (dfcc, ch->fcc, 4); + dfcc[4] = 0; + + bl = 0; + + if (en) { + en->qwOffset = AVI->pos; + en->dwSize = max; + //en->dwDuration = ch->nEntriesInUse -1; // NUMBER OF stream ticks == frames for video/samples for audio + } + +#ifdef DEBUG_ODML + //printf ("ODML Write %s: Entries %ld size %d \n", dfcc, ch->nEntriesInUse, max); +#endif + + //OUTS(ch->fcc); + //OUTD(max); + OUTW(ch->wLongsPerEntry); + OUTC(ch->bIndexSubType); + OUTC(ch->bIndexType); + OUTD(ch->nEntriesInUse); + OUTS(ch->dwChunkId); + OUTD(ch->qwBaseOffset&0xffffffff); + OUTD((ch->qwBaseOffset>>32)&0xffffffff); + OUTD(ch->dwReserved3); + + for (k = 0; k < ch->nEntriesInUse; k++) { + OUTD(ch->aIndex[k].dwOffset); + OUTD(ch->aIndex[k].dwSize); + + } + avi_add_chunk (AVI, ch->fcc, ix00, max); + + free(ix00); + + return 0; +} +#undef OUTS +#undef OUTW +#undef OUTD +#undef OUTC + +// inits a super index structure including its enclosed stdindex +static int avi_init_super_index(avi_t *AVI, unsigned char *idxtag, avisuperindex_chunk **si) +{ + int k; + + avisuperindex_chunk *sil = NULL; + + if ((sil = (avisuperindex_chunk *) malloc (sizeof (avisuperindex_chunk))) == NULL) { + AVI_errno = AVI_ERR_NO_MEM; + return -1; + } + memset(sil, 0, sizeof (avisuperindex_chunk)); + memcpy (sil->fcc, "indx", 4); + sil->dwSize = 0; // size of this chunk + sil->wLongsPerEntry = 4; + sil->bIndexSubType = 0; + sil->bIndexType = AVI_INDEX_OF_INDEXES; + sil->nEntriesInUse = 0; // none are in use + memcpy (sil->dwChunkId, idxtag, 4); + memset (sil->dwReserved, 0, sizeof (sil->dwReserved)); + + // NR_IXNN_CHUNKS == allow 32 indices which means 32 GB files -- arbitrary + sil->aIndex = malloc (sil->wLongsPerEntry * NR_IXNN_CHUNKS * sizeof (uint32_t)); + if (!sil->aIndex) { + AVI_errno = AVI_ERR_NO_MEM; + return -1; + } + memset (sil->aIndex, 0, sil->wLongsPerEntry * NR_IXNN_CHUNKS * sizeof (uint32_t)); + + sil->stdindex = malloc (NR_IXNN_CHUNKS * sizeof (avistdindex_chunk *)); + if (!sil->stdindex) { + AVI_errno = AVI_ERR_NO_MEM; + return -1; + } + for (k = 0; k < NR_IXNN_CHUNKS; k++) { + sil->stdindex[k] = malloc (sizeof (avistdindex_chunk)); + memset(sil->stdindex[k], 0, sizeof (avistdindex_chunk)); + // gets rewritten later + sil->stdindex[k]->qwBaseOffset = (uint64_t)k * NEW_RIFF_THRES; + } + + *si = sil; + + return 0; +} + +// fills an alloc'ed stdindex structure and mallocs some entries for the actual chunks +static int avi_add_std_index(avi_t *AVI, unsigned char *idxtag, unsigned char *strtag, + avistdindex_chunk *stdil) +{ + + memcpy (stdil->fcc, idxtag, 4); + stdil->dwSize = 4096; + stdil->wLongsPerEntry = 2; //sizeof(avistdindex_entry)/sizeof(uint32_t); + stdil->bIndexSubType = 0; + stdil->bIndexType = AVI_INDEX_OF_CHUNKS; + stdil->nEntriesInUse = 0; + + // cp 00db ChunkId + memcpy(stdil->dwChunkId, strtag, 4); + + //stdil->qwBaseOffset = AVI->video_superindex->aIndex[ cur_std_idx ]->qwOffset; + + stdil->aIndex = malloc(stdil->dwSize * sizeof (uint32_t) * stdil->wLongsPerEntry); + + if (!stdil->aIndex) { + AVI_errno = AVI_ERR_NO_MEM; + return -1; + } + + + return 0; +} + +static int avi_add_odml_index_entry_core(avi_t *AVI, long flags, off_t pos, unsigned long len, avistdindex_chunk *si) +{ + int cur_chunk_idx; + // put new chunk into index + si->nEntriesInUse++; + cur_chunk_idx = si->nEntriesInUse-1; + + // need to fetch more memory + if (cur_chunk_idx >= si->dwSize) { + si->dwSize += 4096; + si->aIndex = realloc ( si->aIndex, si->dwSize * sizeof (uint32_t) * si->wLongsPerEntry); + } + + if(len>AVI->max_len) AVI->max_len=len; + + // if bit 31 is set, it is NOT a keyframe + if (flags != 0x10) { + len |= 0x80000000; + } + + si->aIndex [ cur_chunk_idx ].dwSize = len; + si->aIndex [ cur_chunk_idx ].dwOffset = + pos - si->qwBaseOffset + 8; + + //printf("ODML: POS: 0x%lX\n", si->aIndex [ cur_chunk_idx ].dwOffset); + + return 0; +} + +static int avi_add_odml_index_entry(avi_t *AVI, unsigned char *tag, long flags, off_t pos, unsigned long len) +{ + char fcc[5]; + + int audio = (strchr (tag, 'w')?1:0); + int video = !audio; + + unsigned int cur_std_idx; + int audtr; + off_t towrite = 0LL; + + if (video) { + + if (!AVI->video_superindex) { + if (avi_init_super_index(AVI, "ix00", &AVI->video_superindex) < 0) return -1; + AVI->video_superindex->nEntriesInUse++; + cur_std_idx = AVI->video_superindex->nEntriesInUse-1; + + if (avi_add_std_index (AVI, "ix00", "00db", AVI->video_superindex->stdindex[ cur_std_idx ]) < 0) + return -1; + } // init + + } // video + + if (audio) { + + fcc[0] = 'i'; fcc[1] = 'x'; fcc[2] = tag[0]; fcc[3] = tag[1]; fcc[4] = '\0'; + if (!AVI->track[AVI->aptr].audio_superindex) { + +#ifdef DEBUG_ODML + printf("ODML: fcc = %s\n", fcc); +#endif + if (avi_init_super_index(AVI, fcc, &AVI->track[AVI->aptr].audio_superindex) < 0) return -1; + + + AVI->track[AVI->aptr].audio_superindex->nEntriesInUse++; + + snprintf(fcc, sizeof(fcc), "ix%02d", AVI->aptr+1); + if (avi_add_std_index (AVI, fcc, tag, AVI->track[AVI->aptr].audio_superindex->stdindex[ + AVI->track[AVI->aptr].audio_superindex->nEntriesInUse - 1 ]) < 0 + ) return -1; + } // init + + } + + towrite = 0; + if (AVI->video_superindex) { + + cur_std_idx = AVI->video_superindex->nEntriesInUse-1; + towrite += AVI->video_superindex->stdindex[cur_std_idx]->nEntriesInUse*8 + + 4+4+2+1+1+4+4+8+4; + if (cur_std_idx == 0) { + towrite += AVI->n_idx*16 + 8; + towrite += HEADERBYTES; + } + } + + for (audtr=0; audtranum; audtr++) { + if (AVI->track[audtr].audio_superindex) { + cur_std_idx = AVI->track[audtr].audio_superindex->nEntriesInUse-1; + towrite += AVI->track[audtr].audio_superindex->stdindex[cur_std_idx]->nEntriesInUse*8 + + 4+4+2+1+1+4+4+8+4; + } + } + towrite += len + (len&1) + 8; + + //printf("ODML: towrite = 0x%llX = %lld\n", towrite, towrite); + + if (AVI->video_superindex && + (off_t)(AVI->pos+towrite) > (off_t)((off_t)NEW_RIFF_THRES*AVI->video_superindex->nEntriesInUse)) { + + fprintf(stderr, "Adding a new RIFF chunk: %d\n", AVI->video_superindex->nEntriesInUse); + + // rotate ALL indices + AVI->video_superindex->nEntriesInUse++; + cur_std_idx = AVI->video_superindex->nEntriesInUse-1; + + if (AVI->video_superindex->nEntriesInUse > NR_IXNN_CHUNKS) { + fprintf (stderr, "Internal error in avilib - redefine NR_IXNN_CHUNKS\n"); + fprintf (stderr, "[avilib dump] cur_std_idx=%d NR_IXNN_CHUNKS=%d" + "POS=%lld towrite=%lld\n", + cur_std_idx,NR_IXNN_CHUNKS, AVI->pos, towrite); + return -1; + } + + if (avi_add_std_index (AVI, "ix00", "00db", AVI->video_superindex->stdindex[ cur_std_idx ]) < 0) + return -1; + + for (audtr = 0; audtr < AVI->anum; audtr++) { + char aud[5]; + if (!AVI->track[audtr].audio_superindex) { + // not initialized -> no index + continue; + } + AVI->track[audtr].audio_superindex->nEntriesInUse++; + + snprintf(fcc, sizeof(fcc), "ix%02d", audtr+1); + snprintf(aud, sizeof(aud), "0%01dwb", audtr+1); + if (avi_add_std_index (AVI, fcc, aud, AVI->track[audtr].audio_superindex->stdindex[ + AVI->track[audtr].audio_superindex->nEntriesInUse - 1 ]) < 0 + ) return -1; + } + + // write the new riff; + if (cur_std_idx > 0) { + + // dump the _previous_ == already finished index + avi_ixnn_entry (AVI, AVI->video_superindex->stdindex[cur_std_idx - 1], + &AVI->video_superindex->aIndex[cur_std_idx - 1]); + AVI->video_superindex->aIndex[cur_std_idx - 1].dwDuration = + AVI->video_superindex->stdindex[cur_std_idx - 1]->nEntriesInUse - 1; + + for (audtr = 0; audtr < AVI->anum; audtr++) { + + if (!AVI->track[audtr].audio_superindex) { + // not initialized -> no index + continue; + } + avi_ixnn_entry (AVI, AVI->track[audtr].audio_superindex->stdindex[cur_std_idx - 1], + &AVI->track[audtr].audio_superindex->aIndex[cur_std_idx - 1]); + + AVI->track[audtr].audio_superindex->aIndex[cur_std_idx - 1].dwDuration = + AVI->track[audtr].audio_superindex->stdindex[cur_std_idx - 1]->nEntriesInUse - 1; + if (AVI->track[audtr].a_fmt == 0x1) { + AVI->track[audtr].audio_superindex->aIndex[cur_std_idx - 1].dwDuration *= + AVI->track[audtr].a_bits*AVI->track[audtr].a_rate*AVI->track[audtr].a_chans/800; + } + } + + // XXX: dump idx1 structure + if (cur_std_idx == 1) { + avi_add_chunk(AVI, (unsigned char *)"idx1", (unsigned char *)AVI->idx, AVI->n_idx*16); + // qwBaseOffset will contain the start of the second riff chunk + } + // Fix the Offsets later at closing time + avi_add_chunk(AVI, (unsigned char *)"RIFF", "AVIXLIST\0\0\0\0movi", 16); + + AVI->video_superindex->stdindex[ cur_std_idx ]->qwBaseOffset = AVI->pos -16 -8; +#ifdef DEBUG_ODML + printf("ODML: RIFF No.%02d at Offset 0x%llX\n", cur_std_idx, AVI->pos -16 -8); +#endif + + for (audtr = 0; audtr < AVI->anum; audtr++) { + if (AVI->track[audtr].audio_superindex) + AVI->track[audtr].audio_superindex->stdindex[ cur_std_idx ]->qwBaseOffset = + AVI->pos -16 -8; + + } + + // now we can be sure + AVI->is_opendml++; + } + + } + + + if (video) { + avi_add_odml_index_entry_core(AVI, flags, AVI->pos, len, + AVI->video_superindex->stdindex[ AVI->video_superindex->nEntriesInUse-1 ]); + + AVI->total_frames++; + } // video + + if (audio) { + avi_add_odml_index_entry_core(AVI, flags, AVI->pos, len, + AVI->track[AVI->aptr].audio_superindex->stdindex[ + AVI->track[AVI->aptr].audio_superindex->nEntriesInUse-1 ]); + } + + + return 0; +} + +// #undef NR_IXNN_CHUNKS + +static int avi_add_index_entry(avi_t *AVI, unsigned char *tag, long flags, unsigned long pos, unsigned long len) { void *ptr; - if(AVI->n_idx>=AVI->max_idx) - { - ptr = realloc((void *)AVI->idx,(AVI->max_idx+4096)*16); - if(ptr == 0) - { - AVI_errno = AVI_ERR_NO_MEM; - return -1; - } - AVI->max_idx += 4096; - AVI->idx = (uint8_t((*)[16]) ) ptr; + if(AVI->n_idx>=AVI->max_idx) { + ptr = realloc((void *)AVI->idx,(AVI->max_idx+4096)*16); + + if(ptr == 0) { + AVI_errno = AVI_ERR_NO_MEM; + return -1; + } + AVI->max_idx += 4096; + AVI->idx = (unsigned char((*)[16]) ) ptr; } - + /* Add index entry */ + // fprintf(stderr, "INDEX %s %ld %lu %lu\n", tag, flags, pos, len); + memcpy(AVI->idx[AVI->n_idx],tag,4); long2str(AVI->idx[AVI->n_idx]+ 4,flags); - long2str(AVI->idx[AVI->n_idx]+ 8,pos); - long2str(AVI->idx[AVI->n_idx]+12,len); - + long2str(AVI->idx[AVI->n_idx]+ 8, pos); + long2str(AVI->idx[AVI->n_idx]+12, len); + /* Update counter */ AVI->n_idx++; + if(len>AVI->max_len) AVI->max_len=len; + return 0; } +/* Returns 1 if more audio is in that video junk */ +int AVI_can_read_audio(avi_t *AVI) +{ + if(AVI->mode==AVI_MODE_WRITE) { return -1; } + if(!AVI->video_index) { return -1; } + if(!AVI->track[AVI->aptr].audio_index) { return -1; } + + // is it -1? the last ones got left out --tibit + //if (AVI->track[AVI->aptr].audio_posc>=AVI->track[AVI->aptr].audio_chunks-1) { + if (AVI->track[AVI->aptr].audio_posc>=AVI->track[AVI->aptr].audio_chunks) { + return 0; + } + + if (AVI->video_pos >= AVI->video_frames) return 1; + + if (AVI->track[AVI->aptr].audio_index[AVI->track[AVI->aptr].audio_posc].pos < AVI->video_index[AVI->video_pos].pos) return 1; + else return 0; +} /* AVI_open_output_file: Open an AVI File and write a bunch of zero bytes as space for the header. @@ -184,7 +618,8 @@ avi_t* AVI_open_output_file(char * filename) { avi_t *AVI; int i; - uint8_t AVI_header[HEADERBYTES]; + + unsigned char AVI_header[HEADERBYTES]; /* Allocate the avi_t struct and zero it */ @@ -200,7 +635,11 @@ avi_t* AVI_open_output_file(char * filename) we do not truncate the file when we open it. Instead it is truncated when the AVI file is closed */ - AVI->fdes = open(filename,O_RDWR|O_CREAT|O_STREAMING,0644); + // AVI->fdes = open(filename, O_RDWR|O_CREAT|O_BINARY, + // S_IRUSR | S_IWUSR | S_IGRP | S_IROTH); + + AVI->fdes = open(filename, O_RDWR | O_CREAT | O_STREAMING, 0644 ); + if (AVI->fdes < 0) { AVI_errno = AVI_ERR_OPEN; @@ -212,7 +651,7 @@ avi_t* AVI_open_output_file(char * filename) when we are finished with writing */ for (i=0;ifdes,AVI_header,HEADERBYTES); + i = avi_write(AVI->fdes,(char *)AVI_header,HEADERBYTES); if (i != HEADERBYTES) { close(AVI->fdes); @@ -224,10 +663,14 @@ avi_t* AVI_open_output_file(char * filename) AVI->pos = HEADERBYTES; AVI->mode = AVI_MODE_WRITE; /* open for writing */ + //init + AVI->anum = 0; + AVI->aptr = 0; + return AVI; } -void AVI_set_video(avi_t *AVI, int width, int height, double fps, const char *compressor) +void AVI_set_video(avi_t *AVI, int width, int height, double fps, char *compressor) { /* may only be called if file is open for writing */ @@ -236,9 +679,16 @@ void AVI_set_video(avi_t *AVI, int width, int height, double fps, const char *co AVI->width = width; AVI->height = height; AVI->fps = fps; - memcpy(AVI->compressor,compressor,4); + + if(strncmp(compressor, "RGB", 3)==0) { + memset(AVI->compressor, 0, 4); + } else { + memcpy(AVI->compressor,compressor,4); + } + AVI->compressor[4] = 0; + avi_update_header(AVI); } void AVI_set_audio(avi_t *AVI, int channels, long rate, int bits, int format) @@ -247,11 +697,22 @@ void AVI_set_audio(avi_t *AVI, int channels, long rate, int bits, int format) if(AVI->mode==AVI_MODE_READ) return; - AVI->a_chans = channels; - AVI->a_rate = rate; - AVI->a_bits = bits; - AVI->a_fmt = format; + //inc audio tracks + AVI->aptr=AVI->anum; + ++AVI->anum; + if(AVI->anum > AVI_MAX_TRACKS) { + fprintf(stderr, "error - only %d audio tracks supported\n", AVI_MAX_TRACKS); + exit(1); + } + + AVI->track[AVI->aptr].a_chans = channels; + AVI->track[AVI->aptr].a_rate = rate; + AVI->track[AVI->aptr].a_bits = bits; + AVI->track[AVI->aptr].a_fmt = format; +// AVI->track[AVI->aptr].mp3rate = mp3rate; + + avi_update_header(AVI); } #define OUT4CC(s) \ @@ -267,43 +728,43 @@ void AVI_set_audio(avi_t *AVI, int channels, long rate, int bits, int format) } \ nhb += 2 -/* - Write the header of an AVI file and close it. - returns 0 on success, -1 on write error. -*/ +#define OUTCHR(n) \ + if(nhb<=HEADERBYTES-1) { \ + AVI_header[nhb ] = (n )&0xff; \ + } \ + nhb += 1 -static int avi_close_output_file(avi_t *AVI) -{ - - int ret, njunk, sampsize, hasIndex, ms_per_frame, idxerror, flag; - int movi_len, hdrl_start, strl_start; - uint8_t AVI_header[HEADERBYTES]; - long nhb; - - /* Calculate length of movi list */ - - movi_len = AVI->pos - HEADERBYTES + 4; - - /* Try to ouput the index entries. This may fail e.g. if no space - is left on device. We will report this as an error, but we still - try to write the header correctly (so that the file still may be - readable in the most cases */ - - idxerror = 0; - ret = avi_add_chunk(AVI,(const uint8_t*)"idx1",(void*)AVI->idx,AVI->n_idx*16); - hasIndex = (ret==0); - if(ret) - { - idxerror = 1; - AVI_errno = AVI_ERR_WRITE_INDEX; +#define OUTMEM(d, s) \ + { \ + unsigned int s_ = (s); \ + if(nhb <= HEADERBYTES-s_) \ + memcpy(AVI_header+nhb, (d), s_); \ + nhb += s_; \ } - /* Calculate Microseconds per frame */ - if(AVI->fps < 0.001) - ms_per_frame = 0; - else - ms_per_frame = 1000000./AVI->fps + 0.5; +//ThOe write preliminary AVI file header: 0 frames, max vid/aud size +int avi_update_header(avi_t *AVI) +{ + int njunk, sampsize, hasIndex, ms_per_frame, frate, flag; + int movi_len, hdrl_start, strl_start, j; + unsigned char AVI_header[HEADERBYTES]; + long nhb; + unsigned long xd_size, xd_size_align2; + + //assume max size + movi_len = AVI_MAX_LEN - HEADERBYTES + 4; + + //assume index will be written + hasIndex=1; + + if(AVI->fps < 0.001) { + frate=0; + ms_per_frame=0; + } else { + frate = (int) (FRAME_RATE_SCALE*AVI->fps + 0.5); + ms_per_frame=(int) (1000000/AVI->fps + 0.5); + } /* Prepare the file header */ @@ -312,7 +773,7 @@ static int avi_close_output_file(avi_t *AVI) /* The RIFF header */ OUT4CC ("RIFF"); - OUTLONG(AVI->pos - 8); /* # of bytes to follow */ + OUTLONG(movi_len); // assume max size OUT4CC ("AVI "); /* Start the header list */ @@ -336,19 +797,20 @@ static int avi_close_output_file(avi_t *AVI) OUT4CC ("avih"); OUTLONG(56); /* # of bytes to follow */ OUTLONG(ms_per_frame); /* Microseconds per frame */ - OUTLONG(10000000); /* MaxBytesPerSec, I hope this will never be used */ + //ThOe ->0 + // OUTLONG(10000000); /* MaxBytesPerSec, I hope this will never be used */ + OUTLONG(0); OUTLONG(0); /* PaddingGranularity (whatever that might be) */ /* Other sources call it 'reserved' */ - flag = AVIF_WASCAPTUREFILE; + flag = AVIF_ISINTERLEAVED; if(hasIndex) flag |= AVIF_HASINDEX; if(hasIndex && AVI->must_use_index) flag |= AVIF_MUSTUSEINDEX; OUTLONG(flag); /* Flags */ - OUTLONG(AVI->video_frames); /* TotalFrames */ + OUTLONG(0); // no frames yet OUTLONG(0); /* InitialFrames */ - if (AVI->audio_bytes) - { OUTLONG(2); } /* Streams */ - else - { OUTLONG(1); } /* Streams */ + + OUTLONG(AVI->anum+1); + OUTLONG(0); /* SuggestedBufferSize */ OUTLONG(AVI->width); /* Width */ OUTLONG(AVI->height); /* Height */ @@ -369,113 +831,142 @@ static int avi_close_output_file(avi_t *AVI) /* The video stream header */ OUT4CC ("strh"); - OUTLONG(64); /* # of bytes to follow */ + OUTLONG(56); /* # of bytes to follow */ OUT4CC ("vids"); /* Type */ OUT4CC (AVI->compressor); /* Handler */ OUTLONG(0); /* Flags */ OUTLONG(0); /* Reserved, MS says: wPriority, wLanguage */ OUTLONG(0); /* InitialFrames */ - OUTLONG(ms_per_frame); /* Scale */ - OUTLONG(1000000); /* Rate: Rate/Scale == clips/second */ + OUTLONG(FRAME_RATE_SCALE); /* Scale */ + OUTLONG(frate); /* Rate: Rate/Scale == samples/second */ OUTLONG(0); /* Start */ - OUTLONG(AVI->video_frames); /* Length */ + OUTLONG(0); // no frames yet OUTLONG(0); /* SuggestedBufferSize */ OUTLONG(-1); /* Quality */ - OUTLONG(0); /* ClipSize */ - OUTLONG(0); /* Frame */ - OUTLONG(0); /* Frame */ + OUTLONG(0); /* SampleSize */ OUTLONG(0); /* Frame */ OUTLONG(0); /* Frame */ + // OUTLONG(0); /* Frame */ + //OUTLONG(0); /* Frame */ /* The video stream format */ + xd_size = AVI->extradata_size; + xd_size_align2 = (AVI->extradata_size+1) & ~1; + OUT4CC ("strf"); - OUTLONG(40); /* # of bytes to follow */ - OUTLONG(40); /* Size */ + OUTLONG(40 + xd_size_align2);/* # of bytes to follow */ + OUTLONG(40 + xd_size); /* Size */ OUTLONG(AVI->width); /* Width */ OUTLONG(AVI->height); /* Height */ OUTSHRT(1); OUTSHRT(24); /* Planes, Count */ OUT4CC (AVI->compressor); /* Compression */ - OUTLONG(AVI->width*AVI->height); /* SizeImage (in bytes?) */ + // ThOe (*3) + OUTLONG(AVI->width*AVI->height*3); /* SizeImage (in bytes?) */ OUTLONG(0); /* XPelsPerMeter */ OUTLONG(0); /* YPelsPerMeter */ OUTLONG(0); /* ClrUsed: Number of colors used */ OUTLONG(0); /* ClrImportant: Number of colors important */ - /* Finish stream list, i.e. put number of bytes in the list to proper pos */ - - long2str(AVI_header+strl_start-4,nhb-strl_start); - - if (AVI->a_chans && AVI->audio_bytes) - { - - sampsize = avi_sampsize(AVI); - - /* Start the audio stream list ---------------------------------- */ - - OUT4CC ("LIST"); - OUTLONG(0); /* Length of list in bytes, don't know yet */ - strl_start = nhb; /* Store start position */ - OUT4CC ("strl"); - - /* The audio stream header */ - - OUT4CC ("strh"); - OUTLONG(64); /* # of bytes to follow */ - OUT4CC ("auds"); - OUT4CC ("\0\0\0\0"); - OUTLONG(0); /* Flags */ - OUTLONG(0); /* Reserved, MS says: wPriority, wLanguage */ - OUTLONG(0); /* InitialFrames */ - OUTLONG(sampsize); /* Scale */ - OUTLONG(sampsize*AVI->a_rate); /* Rate: Rate/Scale == clips/second */ - OUTLONG(0); /* Start */ - OUTLONG(AVI->audio_bytes/sampsize); /* Length */ - OUTLONG(0); /* SuggestedBufferSize */ - OUTLONG(-1); /* Quality */ - OUTLONG(sampsize); /* ClipSize */ - OUTLONG(0); /* Frame */ - OUTLONG(0); /* Frame */ - OUTLONG(0); /* Frame */ - OUTLONG(0); /* Frame */ - - /* The audio stream format */ - - OUT4CC ("strf"); - OUTLONG(16); /* # of bytes to follow */ - OUTSHRT(AVI->a_fmt); /* Format */ - OUTSHRT(AVI->a_chans); /* Number of channels */ - OUTLONG(AVI->a_rate); /* ClipsPerSec */ - OUTLONG(sampsize*AVI->a_rate); /* AvgBytesPerSec */ - OUTSHRT(sampsize); /* BlockAlign */ - OUTSHRT(AVI->a_bits); /* BitsPerClip */ - - /* Finish stream list, i.e. put number of bytes in the list to proper pos */ - - long2str(AVI_header+strl_start-4,nhb-strl_start); - + // write extradata + if (xd_size > 0 && AVI->extradata) { + OUTMEM(AVI->extradata, xd_size); + if (xd_size != xd_size_align2) { + OUTCHR(0); + } } + /* Finish stream list, i.e. put number of bytes in the list to proper pos */ + + long2str(AVI_header+strl_start-4,nhb-strl_start); + + + /* Start the audio stream list ---------------------------------- */ + + for(j=0; janum; ++j) { + + sampsize = avi_sampsize(AVI, j); + + OUT4CC ("LIST"); + OUTLONG(0); /* Length of list in bytes, don't know yet */ + strl_start = nhb; /* Store start position */ + OUT4CC ("strl"); + + /* The audio stream header */ + + OUT4CC ("strh"); + OUTLONG(56); /* # of bytes to follow */ + OUT4CC ("auds"); + + // ----------- + // ThOe + OUTLONG(0); /* Format (Optionally) */ + // ----------- + + OUTLONG(0); /* Flags */ + OUTLONG(0); /* Reserved, MS says: wPriority, wLanguage */ + OUTLONG(0); /* InitialFrames */ + + // ThOe /4 + OUTLONG(sampsize/4); /* Scale */ + OUTLONG(1000*AVI->track[j].mp3rate/8); + OUTLONG(0); /* Start */ + OUTLONG(4*AVI->track[j].audio_bytes/sampsize); /* Length */ + OUTLONG(0); /* SuggestedBufferSize */ + OUTLONG(-1); /* Quality */ + + // ThOe /4 + OUTLONG(sampsize/4); /* SampleSize */ + + OUTLONG(0); /* Frame */ + OUTLONG(0); /* Frame */ + // OUTLONG(0); /* Frame */ + //OUTLONG(0); /* Frame */ + + /* The audio stream format */ + + OUT4CC ("strf"); + OUTLONG(16); /* # of bytes to follow */ + OUTSHRT(AVI->track[j].a_fmt); /* Format */ + OUTSHRT(AVI->track[j].a_chans); /* Number of channels */ + OUTLONG(AVI->track[j].a_rate); /* SamplesPerSec */ + // ThOe + OUTLONG(1000*AVI->track[j].mp3rate/8); + //ThOe (/4) + + OUTSHRT(sampsize/4); /* BlockAlign */ + + + OUTSHRT(AVI->track[j].a_bits); /* BitsPerSample */ + + /* Finish stream list, i.e. put number of bytes in the list to proper pos */ + + long2str(AVI_header+strl_start-4,nhb-strl_start); + } + /* Finish header list */ - + long2str(AVI_header+hdrl_start-4,nhb-hdrl_start); - + + /* Calculate the needed amount of junk bytes, output junk */ - + njunk = HEADERBYTES - nhb - 8 - 12; - + /* Safety first: if njunk <= 0, somebody has played with HEADERBYTES without knowing what (s)he did. This is a fatal error */ - + if(njunk<=0) - { - mjpeg_error_exit1("AVI_close_output_file: # of header bytes too small"); - } - + { + fprintf(stderr,"AVI_close_output_file: # of header bytes too small\n"); + exit(1); + } + OUT4CC ("JUNK"); OUTLONG(njunk); memset(AVI_header+nhb,0,njunk); + nhb += njunk; /* Start the movi list */ @@ -488,17 +979,721 @@ static int avi_close_output_file(avi_t *AVI) actually written, report an error if someting goes wrong */ if ( lseek(AVI->fdes,0,SEEK_SET)<0 || - write(AVI->fdes,AVI_header,HEADERBYTES)!=HEADERBYTES || + avi_write(AVI->fdes,(char *)AVI_header,HEADERBYTES)!=HEADERBYTES || + lseek(AVI->fdes,AVI->pos,SEEK_SET)<0) + { + AVI_errno = AVI_ERR_CLOSE; + return -1; + } + + return 0; +} + +static int valid_info_tag(char *c) +{ + if (!strncmp(c, "IARL", 4)) return 1; + else if (!strncmp(c, "IART", 4)) return 1; + else if (!strncmp(c, "ICMS", 4)) return 1; + else if (!strncmp(c, "ICMT", 4)) return 1; + else if (!strncmp(c, "ICOP", 4)) return 1; + else if (!strncmp(c, "ICRD", 4)) return 1; + else if (!strncmp(c, "ICRP", 4)) return 1; + else if (!strncmp(c, "IDIM", 4)) return 1; + else if (!strncmp(c, "IDPI", 4)) return 1; + else if (!strncmp(c, "IENG", 4)) return 1; + else if (!strncmp(c, "IGNR", 4)) return 1; + else if (!strncmp(c, "IKEY", 4)) return 1; + else if (!strncmp(c, "ILGT", 4)) return 1; + else if (!strncmp(c, "IMED", 4)) return 1; + else if (!strncmp(c, "INAM", 4)) return 1; + else if (!strncmp(c, "IPLT", 4)) return 1; + else if (!strncmp(c, "IPRD", 4)) return 1; + else if (!strncmp(c, "ISBJ", 4)) return 1; + else if (!strncmp(c, "ISHP", 4)) return 1; + else if (!strncmp(c, "ISRC", 4)) return 1; + else if (!strncmp(c, "ISRF", 4)) return 1; + else if (!strncmp(c, "ITCH", 4)) return 1; + else return 0; + + return 0; +} +// see ../docs/avi_comments.txt +// returns the length of written stream (-1 on error) +static int avi_parse_comments (int fd, char *buf, int space_left) +{ + int len=0, readlen=0, k; + char *data, *c, *d; + struct stat st; + + // safety checks + if (fd<=0 || !buf || space_left<=0) + return -1; + + memset (buf, 0, space_left); + if (fstat (fd, &st) == -1) { + perror ("stat"); + return -1; + } + + if ( !(data = malloc(st.st_size*sizeof(char)+1)) ) { + fprintf(stderr, "malloc failed\n"); + return -1; + } + + readlen = avi_read ( fd, data, st.st_size); + + //printf("Read %d bytes from %d\n", readlen, fd); + + c = data; + space_left--; + + while (len < space_left) { + if ( !c || *c == '\0') + break; // eof; + else if (*c == '#') { // comment, ignore + c = strchr(c, '\n')+1; + } + else if (*c == '\n') { // empty, ignore + c++; + } + else if (*c == 'I') { + + // do not write ISFT -- this is written by transcode + // and important for debugging. + if (!valid_info_tag(c)) { + // skip this line + while (c && *c && *c != '\n' ) { + c++; + } + continue; + } + + // set d after TAG + d = c+4; + + // find first non-blank (!space or !TAB) + while ( d && *d && (*d == ' ' || *d == ' ')) ++d; + if (!d) break; + + // TAG without argument is fine but ignored + if (*d == '\n' || *d == '\r') { + c = d+1; + if (*c == '\n') ++c; + continue; + } + + k = 0; + while (d[k] != '\r' && d[k] != '\n' && d[k] != '\0') ++k; + if (k>=space_left) return len; + + // write TAG + memcpy(buf+len,c,4); + len += 4; + + // write length + '\0' + long2str(buf+len, k+1); len += 4; + + // write comment string + memcpy (buf+len, d, k); + // must be null terminated + *(buf+len+k+1) = '\0'; + + // PAD + if ((k+1)&1) { + k++; + *(buf+len+k+1) = '\0'; + } + len += k+1; + + // advance c + while (*c != '\n' && *c != '\0') ++c; + if (*c != '\0') ++c; + else break; + + } else { + + // ignore junk lines + while (c && *c && *c != '\n' ) { + if (*c == ' ' || *c == ' ') { c++; break; } + c++; + } + if (!c) break; + } + + } + free(data); + + return len; +} + +//SLM +#ifndef S_IRUSR +#define S_IRWXU 00700 /* read, write, execute: owner */ +#define S_IRUSR 00400 /* read permission: owner */ +#define S_IWUSR 00200 /* write permission: owner */ +#define S_IXUSR 00100 /* execute permission: owner */ +#define S_IRWXG 00070 /* read, write, execute: group */ +#define S_IRGRP 00040 /* read permission: group */ +#define S_IWGRP 00020 /* write permission: group */ +#define S_IXGRP 00010 /* execute permission: group */ +#define S_IRWXO 00007 /* read, write, execute: other */ +#define S_IROTH 00004 /* read permission: other */ +#define S_IWOTH 00002 /* write permission: other */ +#define S_IXOTH 00001 /* execute permission: other */ +#endif + +/* + Write the header of an AVI file and close it. + returns 0 on success, -1 on write error. +*/ + +static int avi_close_output_file(avi_t *AVI) +{ + + int ret, njunk, sampsize, hasIndex, ms_per_frame, frate, idxerror, flag; + unsigned long movi_len; + int hdrl_start, strl_start, j; + unsigned char AVI_header[HEADERBYTES]; + long nhb; + unsigned long xd_size, xd_size_align2; + +#ifdef INFO_LIST + long info_len; + long id_len, real_id_len; + long info_start_pos; +// time_t calptr; +#endif + + /* Calculate length of movi list */ + + // dump the rest of the index + if (AVI->is_opendml) { + int cur_std_idx = AVI->video_superindex->nEntriesInUse-1; + int audtr; + +#ifdef DEBUG_ODML + printf("ODML dump the rest indices\n"); +#endif + avi_ixnn_entry (AVI, AVI->video_superindex->stdindex[cur_std_idx], + &AVI->video_superindex->aIndex[cur_std_idx]); + + AVI->video_superindex->aIndex[cur_std_idx].dwDuration = + AVI->video_superindex->stdindex[cur_std_idx]->nEntriesInUse - 1; + + for (audtr = 0; audtr < AVI->anum; audtr++) { + if (!AVI->track[audtr].audio_superindex) { + // not initialized -> no index + continue; + } + avi_ixnn_entry (AVI, AVI->track[audtr].audio_superindex->stdindex[cur_std_idx], + &AVI->track[audtr].audio_superindex->aIndex[cur_std_idx]); + AVI->track[audtr].audio_superindex->aIndex[cur_std_idx].dwDuration = + AVI->track[audtr].audio_superindex->stdindex[cur_std_idx]->nEntriesInUse - 1; + if (AVI->track[audtr].a_fmt == 0x1) { + AVI->track[audtr].audio_superindex->aIndex[cur_std_idx].dwDuration *= + AVI->track[audtr].a_bits*AVI->track[audtr].a_rate*AVI->track[audtr].a_chans/800; + } + } + // The AVI->video_superindex->nEntriesInUse contains the offset + AVI->video_superindex->stdindex[ cur_std_idx+1 ]->qwBaseOffset = AVI->pos; + } + + if (AVI->is_opendml) { + // Correct! + movi_len = AVI->video_superindex->stdindex[ 1 ]->qwBaseOffset - HEADERBYTES+4 - AVI->n_idx*16 - 8; + } else { + movi_len = AVI->pos - HEADERBYTES + 4; + } + + + /* Try to ouput the index entries. This may fail e.g. if no space + is left on device. We will report this as an error, but we still + try to write the header correctly (so that the file still may be + readable in the most cases */ + + idxerror = 0; + hasIndex = 1; + if (!AVI->is_opendml) { + // fprintf(stderr, "pos=%lu, index_len=%ld \n", AVI->pos, AVI->n_idx*16); + ret = avi_add_chunk(AVI, (unsigned char *)"idx1", (unsigned char *)AVI->idx, AVI->n_idx*16); + hasIndex = (ret==0); + //fprintf(stderr, "pos=%lu, index_len=%d\n", AVI->pos, hasIndex); + + if(ret) { + idxerror = 1; + AVI_errno = AVI_ERR_WRITE_INDEX; + } + } + + /* Calculate Microseconds per frame */ + + if(AVI->fps < 0.001) { + frate=0; + ms_per_frame=0; + } else { + frate = (int) (FRAME_RATE_SCALE*AVI->fps + 0.5); + ms_per_frame=(int) (1000000/AVI->fps + 0.5); + } + + /* Prepare the file header */ + + nhb = 0; + + /* The RIFF header */ + + OUT4CC ("RIFF"); + if (AVI->is_opendml) { + OUTLONG(AVI->video_superindex->stdindex[ 1 ]->qwBaseOffset - 8); /* # of bytes to follow */ + } else { + OUTLONG(AVI->pos - 8); /* # of bytes to follow */ + } + + OUT4CC ("AVI "); + + /* Start the header list */ + + OUT4CC ("LIST"); + OUTLONG(0); /* Length of list in bytes, don't know yet */ + hdrl_start = nhb; /* Store start position */ + OUT4CC ("hdrl"); + + /* The main AVI header */ + + /* The Flags in AVI File header */ + +#define AVIF_HASINDEX 0x00000010 /* Index at end of file */ +#define AVIF_MUSTUSEINDEX 0x00000020 +#define AVIF_ISINTERLEAVED 0x00000100 +#define AVIF_TRUSTCKTYPE 0x00000800 /* Use CKType to find key frames */ +#define AVIF_WASCAPTUREFILE 0x00010000 +#define AVIF_COPYRIGHTED 0x00020000 + + OUT4CC ("avih"); + OUTLONG(56); /* # of bytes to follow */ + OUTLONG(ms_per_frame); /* Microseconds per frame */ + //ThOe ->0 + // OUTLONG(10000000); /* MaxBytesPerSec, I hope this will never be used */ + OUTLONG(0); + OUTLONG(0); /* PaddingGranularity (whatever that might be) */ + /* Other sources call it 'reserved' */ + flag = AVIF_ISINTERLEAVED; + if(hasIndex) flag |= AVIF_HASINDEX; + if(hasIndex && AVI->must_use_index) flag |= AVIF_MUSTUSEINDEX; + OUTLONG(flag); /* Flags */ + OUTLONG(AVI->video_frames); /* TotalFrames */ + OUTLONG(0); /* InitialFrames */ + + OUTLONG(AVI->anum+1); +// if (AVI->track[0].audio_bytes) +// { OUTLONG(2); } /* Streams */ +// else +// { OUTLONG(1); } /* Streams */ + + OUTLONG(0); /* SuggestedBufferSize */ + OUTLONG(AVI->width); /* Width */ + OUTLONG(AVI->height); /* Height */ + /* MS calls the following 'reserved': */ + OUTLONG(0); /* TimeScale: Unit used to measure time */ + OUTLONG(0); /* DataRate: Data rate of playback */ + OUTLONG(0); /* StartTime: Starting time of AVI data */ + OUTLONG(0); /* DataLength: Size of AVI data chunk */ + + + /* Start the video stream list ---------------------------------- */ + + OUT4CC ("LIST"); + OUTLONG(0); /* Length of list in bytes, don't know yet */ + strl_start = nhb; /* Store start position */ + OUT4CC ("strl"); + + /* The video stream header */ + + OUT4CC ("strh"); + OUTLONG(56); /* # of bytes to follow */ + OUT4CC ("vids"); /* Type */ + OUT4CC (AVI->compressor); /* Handler */ + OUTLONG(0); /* Flags */ + OUTLONG(0); /* Reserved, MS says: wPriority, wLanguage */ + OUTLONG(0); /* InitialFrames */ + OUTLONG(FRAME_RATE_SCALE); /* Scale */ + OUTLONG(frate); /* Rate: Rate/Scale == samples/second */ + OUTLONG(0); /* Start */ + OUTLONG(AVI->video_frames); /* Length */ + OUTLONG(AVI->max_len); /* SuggestedBufferSize */ + OUTLONG(0); /* Quality */ + OUTLONG(0); /* SampleSize */ + OUTLONG(0); /* Frame */ + OUTLONG(0); /* Frame */ + //OUTLONG(0); /* Frame */ + //OUTLONG(0); /* Frame */ + + /* The video stream format */ + + xd_size = AVI->extradata_size; + xd_size_align2 = (AVI->extradata_size+1) & ~1; + + OUT4CC ("strf"); + OUTLONG(40 + xd_size_align2);/* # of bytes to follow */ + OUTLONG(40 + xd_size); /* Size */ + OUTLONG(AVI->width); /* Width */ + OUTLONG(AVI->height); /* Height */ + OUTSHRT(1); OUTSHRT(24); /* Planes, Count */ + OUT4CC (AVI->compressor); /* Compression */ + // ThOe (*3) + OUTLONG(AVI->width*AVI->height*3); /* SizeImage (in bytes?) */ + OUTLONG(0); /* XPelsPerMeter */ + OUTLONG(0); /* YPelsPerMeter */ + OUTLONG(0); /* ClrUsed: Number of colors used */ + OUTLONG(0); /* ClrImportant: Number of colors important */ + + // write extradata if present + if (xd_size > 0 && AVI->extradata) { + OUTMEM(AVI->extradata, xd_size); + if (xd_size != xd_size_align2) { + OUTCHR(0); + } + } + + // dump index of indices for audio + if (AVI->is_opendml) { + + int k; + + OUT4CC(AVI->video_superindex->fcc); + OUTLONG(2+1+1+4+4+3*4 + AVI->video_superindex->nEntriesInUse * (8+4+4)); + OUTSHRT(AVI->video_superindex->wLongsPerEntry); + OUTCHR(AVI->video_superindex->bIndexSubType); + OUTCHR(AVI->video_superindex->bIndexType); + OUTLONG(AVI->video_superindex->nEntriesInUse); + OUT4CC(AVI->video_superindex->dwChunkId); + OUTLONG(0); + OUTLONG(0); + OUTLONG(0); + + + for (k = 0; k < AVI->video_superindex->nEntriesInUse; k++) { + uint32_t r = (AVI->video_superindex->aIndex[k].qwOffset >> 32) & 0xffffffff; + uint32_t s = (AVI->video_superindex->aIndex[k].qwOffset) & 0xffffffff; + + printf("VID NrEntries %d/%ld (%c%c%c%c) |0x%llX|%ld|%ld|\n", k, + (unsigned long)AVI->video_superindex->nEntriesInUse, + AVI->video_superindex->dwChunkId[0], + AVI->video_superindex->dwChunkId[1], + AVI->video_superindex->dwChunkId[2], + AVI->video_superindex->dwChunkId[3], + (unsigned long long)AVI->video_superindex->aIndex[k].qwOffset, + (unsigned long)AVI->video_superindex->aIndex[k].dwSize, + (unsigned long)AVI->video_superindex->aIndex[k].dwDuration + ); + /* + */ + + OUTLONG(s); + OUTLONG(r); + OUTLONG(AVI->video_superindex->aIndex[k].dwSize); + OUTLONG(AVI->video_superindex->aIndex[k].dwDuration); + } + + } + + /* Finish stream list, i.e. put number of bytes in the list to proper pos */ + + long2str(AVI_header+strl_start-4,nhb-strl_start); + + /* Start the audio stream list ---------------------------------- */ + + for(j=0; janum; ++j) { + + //if (AVI->track[j].a_chans && AVI->track[j].audio_bytes) + { + unsigned long nBlockAlign = 0; + unsigned long avgbsec = 0; + unsigned long scalerate = 0; + + sampsize = avi_sampsize(AVI, j); + sampsize = AVI->track[j].a_fmt==0x1?sampsize*4:sampsize; + + nBlockAlign = (AVI->track[j].a_rate<32000)?576:1152; + /* + printf("XXX sampsize (%d) block (%ld) rate (%ld) audio_bytes (%ld) mp3rate(%ld,%ld)\n", + sampsize, nBlockAlign, AVI->track[j].a_rate, + (long int)AVI->track[j].audio_bytes, + 1000*AVI->track[j].mp3rate/8, AVI->track[j].mp3rate); + */ + + if (AVI->track[j].a_fmt==0x1) { + sampsize = (AVI->track[j].a_chans<2)?sampsize/2:sampsize; + avgbsec = AVI->track[j].a_rate*sampsize/4; + scalerate = AVI->track[j].a_rate*sampsize/4; + } else { + avgbsec = 1000*AVI->track[j].mp3rate/8; + scalerate = 1000*AVI->track[j].mp3rate/8; + } + + OUT4CC ("LIST"); + OUTLONG(0); /* Length of list in bytes, don't know yet */ + strl_start = nhb; /* Store start position */ + OUT4CC ("strl"); + + /* The audio stream header */ + + OUT4CC ("strh"); + OUTLONG(56); /* # of bytes to follow */ + OUT4CC ("auds"); + + // ----------- + // ThOe + OUTLONG(0); /* Format (Optionally) */ + // ----------- + + OUTLONG(0); /* Flags */ + OUTLONG(0); /* Reserved, MS says: wPriority, wLanguage */ + OUTLONG(0); /* InitialFrames */ + + // VBR + if (AVI->track[j].a_fmt == 0x55 && AVI->track[j].a_vbr) { + OUTLONG(nBlockAlign); /* Scale */ + OUTLONG(AVI->track[j].a_rate); /* Rate */ + OUTLONG(0); /* Start */ + OUTLONG(AVI->track[j].audio_chunks); /* Length */ + OUTLONG(0); /* SuggestedBufferSize */ + OUTLONG(0); /* Quality */ + OUTLONG(0); /* SampleSize */ + OUTLONG(0); /* Frame */ + OUTLONG(0); /* Frame */ + } else { + OUTLONG(sampsize/4); /* Scale */ + OUTLONG(scalerate); /* Rate */ + OUTLONG(0); /* Start */ + OUTLONG(4*AVI->track[j].audio_bytes/sampsize); /* Length */ + OUTLONG(0); /* SuggestedBufferSize */ + OUTLONG(0xffffffff); /* Quality */ + OUTLONG(sampsize/4); /* SampleSize */ + OUTLONG(0); /* Frame */ + OUTLONG(0); /* Frame */ + } + + /* The audio stream format */ + + OUT4CC ("strf"); + + if (AVI->track[j].a_fmt == 0x55 && AVI->track[j].a_vbr) { + + OUTLONG(30); /* # of bytes to follow */ // mplayer writes 28 + OUTSHRT(AVI->track[j].a_fmt); /* Format */ // 2 + OUTSHRT(AVI->track[j].a_chans); /* Number of channels */ // 2 + OUTLONG(AVI->track[j].a_rate); /* SamplesPerSec */ // 4 + //ThOe/tibit + OUTLONG(1000*AVI->track[j].mp3rate/8); /* maybe we should write an avg. */ // 4 + OUTSHRT(nBlockAlign); /* BlockAlign */ // 2 + OUTSHRT(AVI->track[j].a_bits); /* BitsPerSample */ // 2 + + OUTSHRT(12); /* cbSize */ // 2 + OUTSHRT(1); /* wID */ // 2 + OUTLONG(2); /* fdwFlags */ // 4 + OUTSHRT(nBlockAlign); /* nBlockSize */ // 2 + OUTSHRT(1); /* nFramesPerBlock */ // 2 + OUTSHRT(0); /* nCodecDelay */ // 2 + + } else if (AVI->track[j].a_fmt == 0x55 && !AVI->track[j].a_vbr) { + + OUTLONG(30); /* # of bytes to follow */ + OUTSHRT(AVI->track[j].a_fmt); /* Format */ + OUTSHRT(AVI->track[j].a_chans); /* Number of channels */ + OUTLONG(AVI->track[j].a_rate); /* SamplesPerSec */ + //ThOe/tibit + OUTLONG(1000*AVI->track[j].mp3rate/8); + OUTSHRT(sampsize/4); /* BlockAlign */ + OUTSHRT(AVI->track[j].a_bits); /* BitsPerSample */ + + OUTSHRT(12); /* cbSize */ + OUTSHRT(1); /* wID */ + OUTLONG(2); /* fdwFlags */ + OUTSHRT(nBlockAlign); /* nBlockSize */ + OUTSHRT(1); /* nFramesPerBlock */ + OUTSHRT(0); /* nCodecDelay */ + + } else { + + OUTLONG(18); /* # of bytes to follow */ + OUTSHRT(AVI->track[j].a_fmt); /* Format */ + OUTSHRT(AVI->track[j].a_chans); /* Number of channels */ + OUTLONG(AVI->track[j].a_rate); /* SamplesPerSec */ + //ThOe/tibit + OUTLONG(avgbsec); /* Avg bytes/sec */ + OUTSHRT(sampsize/4); /* BlockAlign */ + OUTSHRT(AVI->track[j].a_bits); /* BitsPerSample */ + OUTSHRT(0); /* cbSize */ + + } + } + if (AVI->is_opendml) { + + int k ; + + if (!AVI->track[j].audio_superindex) { + // not initialized -> no index + continue; + } + + OUT4CC(AVI->track[j].audio_superindex->fcc); /* "indx" */ + OUTLONG(2+1+1+4+4+3*4 + AVI->track[j].audio_superindex->nEntriesInUse * (8+4+4)); + OUTSHRT(AVI->track[j].audio_superindex->wLongsPerEntry); + OUTCHR(AVI->track[j].audio_superindex->bIndexSubType); + OUTCHR(AVI->track[j].audio_superindex->bIndexType); + OUTLONG(AVI->track[j].audio_superindex->nEntriesInUse); + OUT4CC(AVI->track[j].audio_superindex->dwChunkId); + OUTLONG(0); OUTLONG(0); OUTLONG(0); + + for (k = 0; k < AVI->track[j].audio_superindex->nEntriesInUse; k++) { + uint32_t r = (AVI->track[j].audio_superindex->aIndex[k].qwOffset >> 32) & 0xffffffff; + uint32_t s = (AVI->track[j].audio_superindex->aIndex[k].qwOffset) & 0xffffffff; + + /* + printf("AUD[%d] NrEntries %d/%ld (%c%c%c%c) |0x%llX|%ld|%ld| \n", j, k, + AVI->track[j].audio_superindex->nEntriesInUse, + AVI->track[j].audio_superindex->dwChunkId[0], AVI->track[j].audio_superindex->dwChunkId[1], + AVI->track[j].audio_superindex->dwChunkId[2], AVI->track[j].audio_superindex->dwChunkId[3], + AVI->track[j].audio_superindex->aIndex[k].qwOffset, + AVI->track[j].audio_superindex->aIndex[k].dwSize, + AVI->track[j].audio_superindex->aIndex[k].dwDuration + ); + */ + + OUTLONG(s); + OUTLONG(r); + OUTLONG(AVI->track[j].audio_superindex->aIndex[k].dwSize); + OUTLONG(AVI->track[j].audio_superindex->aIndex[k].dwDuration); + } + } + /* Finish stream list, i.e. put number of bytes in the list to proper pos */ + long2str(AVI_header+strl_start-4,nhb-strl_start); + } + + if (AVI->is_opendml) { + OUT4CC("LIST"); + OUTLONG(16); + OUT4CC("odml"); + OUT4CC("dmlh"); + OUTLONG(4); + OUTLONG(AVI->total_frames); + } + + /* Finish header list */ + + long2str(AVI_header+hdrl_start-4,nhb-hdrl_start); + + + // add INFO list --- (0.6.0pre4) + +#ifdef INFO_LIST + OUT4CC ("LIST"); + + info_start_pos = nhb; + info_len = MAX_INFO_STRLEN + 12; + OUTLONG(info_len); // rewritten later + OUT4CC ("INFO"); + + OUT4CC ("ISFT"); + //OUTLONG(MAX_INFO_STRLEN); + memset(id_str, 0, MAX_INFO_STRLEN); + + snprintf(id_str, sizeof(id_str), "%s-%s", PACKAGE, VERSION); + real_id_len = id_len = strlen(id_str)+1; + if (id_len&1) id_len++; + + OUTLONG(real_id_len); + + memset(AVI_header+nhb, 0, id_len); + memcpy(AVI_header+nhb, id_str, id_len); + nhb += id_len; + + info_len = avi_parse_comments (AVI->comment_fd, AVI_header+nhb, HEADERBYTES - nhb - 8 - 12); + if (info_len <= 0) info_len=0; + + // write correct len + long2str(AVI_header+info_start_pos, info_len + id_len + 4+4+4); + + nhb += info_len; + +// OUT4CC ("ICMT"); +// OUTLONG(MAX_INFO_STRLEN); + +// calptr=time(NULL); +// snprintf(id_str, sizeof(id_str), "\t%s %s", ctime(&calptr), ""); +// memset(AVI_header+nhb, 0, MAX_INFO_STRLEN); +// memcpy(AVI_header+nhb, id_str, 25); +// nhb += MAX_INFO_STRLEN; +#endif + + // ---------------------------- + + /* Calculate the needed amount of junk bytes, output junk */ + + njunk = HEADERBYTES - nhb - 8 - 12; + + /* Safety first: if njunk <= 0, somebody has played with + HEADERBYTES without knowing what (s)he did. + This is a fatal error */ + + if(njunk<=0) + { + fprintf(stderr,"AVI_close_output_file: # of header bytes too small\n"); + exit(1); + } + + OUT4CC ("JUNK"); + OUTLONG(njunk); + memset(AVI_header+nhb,0,njunk); + + nhb += njunk; + + /* Start the movi list */ + + OUT4CC ("LIST"); + OUTLONG(movi_len); /* Length of list in bytes */ + OUT4CC ("movi"); + + /* Output the header, truncate the file to the number of bytes + actually written, report an error if someting goes wrong */ + + if ( lseek(AVI->fdes,0,SEEK_SET)<0 || + avi_write(AVI->fdes,(char *)AVI_header,HEADERBYTES)!=HEADERBYTES || ftruncate(AVI->fdes,AVI->pos)<0 ) { AVI_errno = AVI_ERR_CLOSE; return -1; } + + // Fix up the empty additional RIFF and LIST chunks + if (AVI->is_opendml) { + int k = 0; + char f[4]; + unsigned int len; + + for (k=1; kvideo_superindex->nEntriesInUse; k++) { + // the len of the RIFF Chunk + lseek(AVI->fdes, AVI->video_superindex->stdindex[k]->qwBaseOffset+4, SEEK_SET); + len = AVI->video_superindex->stdindex[k+1]->qwBaseOffset - + AVI->video_superindex->stdindex[k]->qwBaseOffset - 8; + long2str(f, len); + avi_write(AVI->fdes, f, 4); + + // len of the LIST/movi chunk + lseek(AVI->fdes, 8, SEEK_CUR); + len -= 12; + long2str(f, len); + avi_write(AVI->fdes, f, 4); + } + } + + if(idxerror) return -1; return 0; } + /* AVI_write_data: Add video or audio data to the file; @@ -509,51 +1704,67 @@ static int avi_close_output_file(avi_t *AVI) */ -static int avi_write_data(avi_t *AVI, uint8_t *data, long length, int audio) +static int avi_write_data(avi_t *AVI, char *data, unsigned long length, int audio, int keyframe) { - int n; + int n = 0; + unsigned char astr[5]; + + // transcode core itself checks for the size -- unneeded and + // does harm to xvid 2pass encodes where the first pass can get + // _very_ large -- tibit. + +#if 0 /* Check for maximum file length */ - - if ( (AVI->pos + 8 + length + 8 + (AVI->n_idx+1)*16) > AVI_MAX_LEN ) - { - AVI_errno = AVI_ERR_SIZELIM; - return -1; + + if ( (AVI->pos + 8 + length + 8 + (AVI->n_idx+1)*16) > AVI_MAX_LEN ) { + AVI_errno = AVI_ERR_SIZELIM; + return -1; } - +#endif + /* Add index entry */ - if(audio) - n = avi_add_index_entry(AVI,(const uint8_t*)"01wb",0x00,AVI->pos,length); - else - n = avi_add_index_entry(AVI,(const uint8_t*)"00db",0x10,AVI->pos,length); + //set tag for current audio track + snprintf((char *)astr, sizeof(astr), "0%1dwb", (int)(AVI->aptr+1)); + if(audio) { + if (!AVI->is_opendml) n = avi_add_index_entry(AVI,astr,0x10,AVI->pos,length); + n += avi_add_odml_index_entry(AVI,astr,0x10,AVI->pos,length); + } else { + if (!AVI->is_opendml) n = avi_add_index_entry(AVI,(unsigned char *)"00db",((keyframe)?0x10:0x0),AVI->pos,length); + n += avi_add_odml_index_entry(AVI,(unsigned char *)"00db",((keyframe)?0x10:0x0),AVI->pos,length); + } + if(n) return -1; - + /* Output tag and data */ - + if(audio) - n = avi_add_chunk(AVI,(const uint8_t*)"01wb",data,length); + n = avi_add_chunk(AVI,(unsigned char *)astr,data,length); else - n = avi_add_chunk(AVI,(const uint8_t*)"00db",data,length); - + n = avi_add_chunk(AVI,(unsigned char *)"00db",data,length); + if (n) return -1; - + return 0; } -int AVI_write_frame(avi_t *AVI, uint8_t *data, long bytes) +int AVI_write_frame(avi_t *AVI, char *data, long bytes) { - long pos; + int keyframe = 1; //@everything is a keyframe in veejay + off_t pos; + + if(AVI->mode==AVI_MODE_READ) { AVI_errno = AVI_ERR_NOT_PERM; return -1; } + + pos = AVI->pos; - if(AVI->mode==AVI_MODE_READ) { AVI_errno = AVI_ERR_NOT_PERM; return -1; } - - pos = AVI->pos; - if( avi_write_data(AVI,data,bytes,0) ) return -1; - AVI->last_pos = pos; - AVI->last_len = bytes; - AVI->video_frames++; - return 0; + if(avi_write_data(AVI,data,bytes,0,keyframe)) return -1; + + AVI->last_pos = pos; + AVI->last_len = bytes; + AVI->video_frames++; + return 0; } int AVI_dup_frame(avi_t *AVI) @@ -561,21 +1772,62 @@ int AVI_dup_frame(avi_t *AVI) if(AVI->mode==AVI_MODE_READ) { AVI_errno = AVI_ERR_NOT_PERM; return -1; } if(AVI->last_pos==0) return 0; /* No previous real frame */ - if(avi_add_index_entry(AVI,(const uint8_t*)"00db",0x10,AVI->last_pos,AVI->last_len)) return -1; + if(avi_add_index_entry(AVI,(unsigned char *)"00db",0x10,AVI->last_pos,AVI->last_len)) return -1; AVI->video_frames++; AVI->must_use_index = 1; return 0; } -int AVI_write_audio(avi_t *AVI, uint8_t *data, long bytes) +int AVI_write_audio(avi_t *AVI, char *data, long bytes) { if(AVI->mode==AVI_MODE_READ) { AVI_errno = AVI_ERR_NOT_PERM; return -1; } - if( avi_write_data(AVI,data,bytes,1) ) return -1; - AVI->audio_bytes += bytes; + if( avi_write_data(AVI,data,bytes,1,0) ) return -1; + AVI->track[AVI->aptr].audio_bytes += bytes; + AVI->track[AVI->aptr].audio_chunks++; return 0; } + +int AVI_append_audio(avi_t *AVI, char *data, long bytes) +{ + + // won't work for >2gb + long i, length, pos; + unsigned char c[4]; + + if(AVI->mode==AVI_MODE_READ) { AVI_errno = AVI_ERR_NOT_PERM; return -1; } + + // update last index entry: + + --AVI->n_idx; + length = str2ulong(AVI->idx[AVI->n_idx]+12); + pos = str2ulong(AVI->idx[AVI->n_idx]+8); + + //update; + long2str(AVI->idx[AVI->n_idx]+12,length+bytes); + + ++AVI->n_idx; + + AVI->track[AVI->aptr].audio_bytes += bytes; + + //update chunk header + lseek(AVI->fdes, pos+4, SEEK_SET); + long2str(c, length+bytes); + avi_write(AVI->fdes, (char *)c, 4); + + lseek(AVI->fdes, pos+8+length, SEEK_SET); + + i=PAD_EVEN(length + bytes); + + bytes = i - length; + avi_write(AVI->fdes, data, bytes); + AVI->pos = pos + 8 + i; + + return 0; +} + + long AVI_bytes_remain(avi_t *AVI) { if(AVI->mode==AVI_MODE_READ) return 0; @@ -583,6 +1835,48 @@ long AVI_bytes_remain(avi_t *AVI) return ( AVI_MAX_LEN - (AVI->pos + 8 + 16*AVI->n_idx)); } +long AVI_bytes_written(avi_t *AVI) +{ + if(AVI->mode==AVI_MODE_READ) return 0; + + return (AVI->pos + 8 + 16*AVI->n_idx); +} + +int AVI_set_audio_track(avi_t *AVI, int track) +{ + + if(track < 0 || track + 1 > AVI->anum) return(-1); + + //this info is not written to file anyway + AVI->aptr=track; + return 0; +} + +int AVI_get_audio_track(avi_t *AVI) +{ + return(AVI->aptr); +} + +void AVI_set_audio_vbr(avi_t *AVI, long is_vbr) +{ + AVI->track[AVI->aptr].a_vbr = is_vbr; +} + +long AVI_get_audio_vbr(avi_t *AVI) +{ + return(AVI->track[AVI->aptr].a_vbr); +} + +void AVI_set_comment_fd(avi_t *AVI, int fd) +{ + AVI->comment_fd = fd; +} +int AVI_get_comment_fd(avi_t *AVI) +{ + return AVI->comment_fd; +} + + /******************************************************************* * * * Utilities for reading video and audio from an AVI File * @@ -592,6 +1886,7 @@ long AVI_bytes_remain(avi_t *AVI) int AVI_close(avi_t *AVI) { int ret; + int j,k; /* If the file was open for writing, the header and index still have to be written */ @@ -601,26 +1896,63 @@ int AVI_close(avi_t *AVI) else ret = 0; - /* Even if there happened a error, we first clean up */ + /* Even if there happened an error, we first clean up */ + if( AVI->mmap_region ) + mmap_free( AVI->mmap_region ); - mmap_free( AVI->mmap_region ); - + if (AVI->comment_fd>0) + close(AVI->comment_fd); + AVI->comment_fd = -1; close(AVI->fdes); if(AVI->idx) free(AVI->idx); if(AVI->video_index) free(AVI->video_index); - if(AVI->audio_index) free(AVI->audio_index); + if(AVI->video_superindex && AVI->video_superindex->stdindex) { + for (j = 0; j < NR_IXNN_CHUNKS; j++) { + if (AVI->video_superindex->stdindex[j]) { + if (AVI->video_superindex->stdindex[j]->aIndex) { + free(AVI->video_superindex->stdindex[j]->aIndex); + } + free(AVI->video_superindex->stdindex[j]); + } + } + if(AVI->video_superindex->stdindex) free(AVI->video_superindex->stdindex); + if(AVI->video_superindex->aIndex) free(AVI->video_superindex->aIndex); + free(AVI->video_superindex); + } + + for (j=0; janum; j++) + { + if(AVI->track[j].audio_index) free(AVI->track[j].audio_index); + if(AVI->track[j].audio_superindex) { + // shortcut + avisuperindex_chunk *a = AVI->track[j].audio_superindex; + for (k = 0; k < NR_IXNN_CHUNKS; k++) { + if (a->stdindex && a->stdindex[k]) { + if (a->stdindex[k]->aIndex) { + free(a->stdindex[k]->aIndex); + } + free(a->stdindex[k]); + } + } + if(a->stdindex) free(a->stdindex); + if(a->aIndex) free(a->aIndex); + free(a); + } + } + + if (AVI->bitmap_info_header) + free(AVI->bitmap_info_header); + for (j = 0; j < AVI->anum; j++) + if (AVI->wave_format_ex[j]) + free(AVI->wave_format_ex[j]); + free(AVI); + AVI=NULL; return ret; } -int AVI_fileno(avi_t *AVI) -{ - return AVI->fdes; -} - - #define ERR_EXIT(x) \ { \ AVI_close(AVI); \ @@ -628,60 +1960,323 @@ int AVI_fileno(avi_t *AVI) return 0; \ } -avi_t *AVI_open_input_file(char *filename, int getIndex, int mmap_size) +avi_t *AVI_open_input_indexfile(char *filename, int getIndex, char *indexfile) { - avi_t *AVI; - long i, n, rate, scale, idx_type; - uint8_t *hdrl_data; - long hdrl_len = 0; - long nvi, nai, ioff; - long tot; - int lasttag = 0; - int vids_strh_seen = 0; - int vids_strf_seen = 0; - int auds_strh_seen = 0; - int auds_strf_seen = 0; - int num_stream = 0; - uint8_t data[256]; - struct stat s; - - /* Create avi_t structure */ - - AVI = (avi_t *) malloc(sizeof(avi_t)); - if(AVI==NULL) - { + avi_t *AVI=NULL; + + /* Create avi_t structure */ + + AVI = (avi_t *) malloc(sizeof(avi_t)); + if(AVI==NULL) + { AVI_errno = AVI_ERR_NO_MEM; - return NULL; - } - memset((void *)AVI,0,sizeof(avi_t)); + return 0; + } + memset((void *)AVI,0,sizeof(avi_t)); + + AVI->mode = AVI_MODE_READ; /* open for reading */ + + /* Open the file */ - AVI->mode = AVI_MODE_READ; /* open for reading */ - - /* Open the file */ - - AVI->fdes = open(filename,O_RDONLY|O_STREAMING); - if(AVI->fdes < 0) - { +#if defined(SYS_WINDOWS) + AVI->fdes = open(filename,O_RDONLY|O_BINARY); +#else + AVI->fdes = open(filename,O_RDONLY); +#endif + if(AVI->fdes < 0) + { AVI_errno = AVI_ERR_OPEN; free(AVI); - return NULL; - } + return 0; + } + + off_t len = lseek( AVI->fdes, 0, SEEK_END ); + if( len <= (HEADERBYTES+16)) + { + AVI_errno = AVI_ERR_EMPTY; + free(AVI); + return 0; + } + lseek( AVI->fdes,0,SEEK_SET ); - off_t len = lseek( AVI->fdes, 0, SEEK_END ); - if( len <= (HEADERBYTES+16)) - { - AVI_errno = AVI_ERR_EMPTY; - free(AVI); - return NULL; - } - lseek(AVI->fdes,0,SEEK_SET); + + AVI->index_file=strdup(indexfile); + AVI_errno = 0; + avi_parse_input_file(AVI, getIndex); - /* Read first 12 bytes and check that this is an AVI file */ + if (AVI != NULL && !AVI_errno) { + AVI->aptr=0; //reset + } - if( read(AVI->fdes,data,12) != 12 ) ERR_EXIT(AVI_ERR_READ) + if (AVI_errno) + return AVI=NULL; + else + return AVI; +} - if( strncasecmp((char*)data ,"RIFF",4) !=0 || - strncasecmp((char*)data+8,"AVI ",4) !=0 ) ERR_EXIT(AVI_ERR_NO_AVI) +avi_t *AVI_open_indexfd(int fd, int getIndex, char *indexfile) +{ + avi_t *AVI=NULL; + + /* Create avi_t structure */ + + AVI = (avi_t *) malloc(sizeof(avi_t)); + if(AVI==NULL) + { + AVI_errno = AVI_ERR_NO_MEM; + return 0; + } + memset((void *)AVI,0,sizeof(avi_t)); + + AVI->mode = AVI_MODE_READ; /* open for reading */ + + // file alread open + AVI->fdes = fd; + + AVI->index_file=strdup(indexfile); + AVI_errno = 0; + avi_parse_input_file(AVI, getIndex); + + if (AVI != NULL && !AVI_errno) { + AVI->aptr=0; //reset + } + + if (AVI_errno) + return AVI=NULL; + else + return AVI; +} + + +avi_t *AVI_open_input_file(char *filename, int getIndex, int mmap_size) +{ + avi_t *AVI=NULL; + + /* Create avi_t structure */ + + AVI = (avi_t *) malloc(sizeof(avi_t)); + if(AVI==NULL) + { + AVI_errno = AVI_ERR_NO_MEM; + return 0; + } + memset((void *)AVI,0,sizeof(avi_t)); + + AVI->mode = AVI_MODE_READ; /* open for reading */ + + /* Open the file */ + + AVI->fdes = open(filename,O_RDONLY); + if(AVI->fdes < 0) + { + AVI_errno = AVI_ERR_OPEN; + free(AVI); + return 0; + } + + AVI_errno = 0; + avi_parse_input_file(AVI, getIndex); + + if (AVI != NULL && !AVI_errno) { + AVI->aptr=0; //reset + } + + if (AVI_errno) + return AVI=NULL; + else + return AVI; +} + +avi_t *AVI_open_fd(int fd, int getIndex, int mmap_size) +{ + avi_t *AVI=NULL; + + /* Create avi_t structure */ + + AVI = (avi_t *) malloc(sizeof(avi_t)); + if(AVI==NULL) + { + AVI_errno = AVI_ERR_NO_MEM; + return 0; + } + memset((void *)AVI,0,sizeof(avi_t)); + + AVI->mode = AVI_MODE_READ; /* open for reading */ + + // file alread open + AVI->fdes = fd; + + AVI_errno = 0; + avi_parse_input_file(AVI, getIndex); + + if (AVI != NULL && !AVI_errno) { + AVI->aptr=0; //reset + } + + + if(!AVI_errno) + { + long file_size = (long)lseek( AVI->fdes, 0, SEEK_END ); + lseek( AVI->fdes, AVI->movi_start, SEEK_SET ); + AVI->mmap_size = AVI->width * AVI->height * mmap_size; + if(AVI->mmap_size > 0 ) + { + AVI->mmap_region = + mmap_file( AVI->fdes,0,AVI->mmap_size,file_size ); + } + } + + + if (AVI_errno) + return AVI=NULL; + else + return AVI; +} + +// transcode-0.6.8 +// reads a file generated by aviindex and builds the index out of it. + +int avi_parse_index_from_file(avi_t *AVI, char *filename) +{ + char data[100]; // line buffer + FILE *fd = NULL; // read from + off_t pos, len, f_pos, tot_chunks[AVI_MAX_TRACKS]; + int key=0, type; + int vid_chunks=0, aud_chunks[AVI_MAX_TRACKS]; + long line_count=0; + char *c, d; + int i,j; + + for (i=0; ivideo_index) { + free(AVI->video_index); + AVI->video_index = NULL; + } + + for(j=0; janum; ++j) { + if(AVI->track[j].audio_index) { + free(AVI->track[j].audio_index); + } + AVI->track[j].audio_index = NULL; + AVI->track[j].audio_chunks = 0; + } + + if (!(fd = fopen(filename, "r"))) { perror ("avi_parse_index_from_file: fopen"); return -1; } + + // read header + fgets(data, 100, fd); + + if ( strncasecmp(data, "AVIIDX1", 7) != 0) { + fprintf(stderr, "%s: Not an AVI index file\n", filename); + return -1; + } + + // read comment + fgets(data, 100, fd); + f_pos = ftell(fd); + while (fgets(data, 100, fd)) { + d = data[5] - '1'; + if (d == 0) { + vid_chunks++; + } else if (d == 1 || d == 2 || d == 3 || d == 4 || + d == 5 || d == 6 || d == 7 || d == 8 ) { + aud_chunks[d-1]++; + } else + continue; + + line_count++; + } + + AVI->video_frames = vid_chunks; + for(j=0; janum; ++j) AVI->track[j].audio_chunks = aud_chunks[j]; + + if(AVI->video_frames==0) ERR_EXIT(AVI_ERR_NO_VIDS); + AVI->video_index = (video_index_entry *) malloc(vid_chunks*sizeof(video_index_entry)); + if(AVI->video_index==0) ERR_EXIT(AVI_ERR_NO_MEM); + + for(j=0; janum; ++j) { + if(AVI->track[j].audio_chunks) { + AVI->track[j].audio_index = (audio_index_entry *) malloc(aud_chunks[j]*sizeof(audio_index_entry)); + if(AVI->track[j].audio_index==0) ERR_EXIT(AVI_ERR_NO_MEM); + } + } + + // reset after header + fseek(fd, f_pos, SEEK_SET); + + vid_chunks = 0; + for(j=0; janum; ++j) aud_chunks[j] = tot_chunks[j] = 0; + + while (fgets(data, 100, fd)) { + // this is very slow + // sscanf(data, "%*s %d %*d %*d %lld %lld %d %*f", &type, &pos, &len, &key); + c = strchr (data, ' '); + type = strtol(c+1, &c, 10); + //ch = strtol(c+1, &c, 10); + c = strchr(c+1, ' '); + //chtype= strtol(c+1, &c, 10); + c = strchr(c+1, ' '); + pos = strtoll(c+1, &c, 10); + len = strtol(c+1, &c, 10); + key = strtol(c+1, &c, 10); + //ms = strtod(c+1, NULL); + i = type-1; + + switch (i) { + case 0: // video + AVI->video_index[vid_chunks].key = (off_t)(key?0x10:0); + AVI->video_index[vid_chunks].pos = pos+8; + AVI->video_index[vid_chunks].len = len; + vid_chunks++; + break; + case 1: case 2: case 3: case 4: + case 5: case 6: case 7: case 8: + j=i-1; + AVI->track[j].audio_index[aud_chunks[j]].pos = pos+8; + AVI->track[j].audio_index[aud_chunks[j]].len = len; + AVI->track[j].audio_index[aud_chunks[j]].tot = tot_chunks[j]; + tot_chunks[j] += AVI->track[j].audio_index[aud_chunks[j]].len; + aud_chunks[j]++; + break; + default: + continue; + } + + } + for(j=0; janum; ++j) AVI->track[j].audio_bytes = tot_chunks[j]; + + fclose (fd); + + return 0; +} + +int avi_parse_input_file(avi_t *AVI, int getIndex) +{ + long i, rate, scale, idx_type; + off_t n; + unsigned char *hdrl_data; + long header_offset=0, hdrl_len=0; + long nvi, nai[AVI_MAX_TRACKS], ioff; + long tot[AVI_MAX_TRACKS]; + int j; + int lasttag = 0; + int vids_strh_seen = 0; + int vids_strf_seen = 0; + int auds_strh_seen = 0; + // int auds_strf_seen = 0; + int num_stream = 0; + char data[256]; + off_t oldpos=-1, newpos=-1; + + /* Read first 12 bytes and check that this is an AVI file */ + + if( avi_read(AVI->fdes,data,12) != 12 ) ERR_EXIT(AVI_ERR_READ) + + if( strncasecmp(data ,"RIFF",4) !=0 || + strncasecmp(data+8,"AVI ",4) !=0 ) ERR_EXIT(AVI_ERR_NO_AVI) /* Go through the AVI file and extract the header list, the start position of the 'movi' list and an optionally @@ -689,41 +2284,56 @@ avi_t *AVI_open_input_file(char *filename, int getIndex, int mmap_size) hdrl_data = 0; + while(1) { - if( read(AVI->fdes,data,8) != 8 ) break; /* We assume it's EOF */ + if( avi_read(AVI->fdes,data,8) != 8 ) break; /* We assume it's EOF */ + newpos=lseek(AVI->fdes,0,SEEK_CUR); + if(oldpos==newpos) { + /* This is a broken AVI stream... */ + return -1; + } + oldpos=newpos; - n = str2ulong(data+4); + n = str2ulong((unsigned char *)data+4); n = PAD_EVEN(n); - if(strncasecmp((char*)data,"LIST",4) == 0) + if(strncasecmp(data,"LIST",4) == 0) { - if( read(AVI->fdes,data,4) != 4 ) ERR_EXIT(AVI_ERR_READ) + if( avi_read(AVI->fdes,data,4) != 4 ) ERR_EXIT(AVI_ERR_READ) n -= 4; - if(strncasecmp((char*)data,"hdrl",4) == 0) + if(strncasecmp(data,"hdrl",4) == 0) { hdrl_len = n; - hdrl_data = (uint8_t *) malloc(n); - if(hdrl_data==0) ERR_EXIT(AVI_ERR_NO_MEM) - if( read(AVI->fdes,hdrl_data,n) != n ) ERR_EXIT(AVI_ERR_READ) + hdrl_data = (unsigned char *) malloc(n); + if(hdrl_data==0) ERR_EXIT(AVI_ERR_NO_MEM); + + // offset of header + + header_offset = lseek(AVI->fdes,0,SEEK_CUR); + + if( avi_read(AVI->fdes,(char *)hdrl_data,n) != n ) ERR_EXIT(AVI_ERR_READ) } - else if(strncasecmp((char*)data,"movi",4) == 0) + else if(strncasecmp(data,"movi",4) == 0) { AVI->movi_start = lseek(AVI->fdes,0,SEEK_CUR); - lseek(AVI->fdes,n,SEEK_CUR); + if (lseek(AVI->fdes,n,SEEK_CUR)==(off_t)-1) break; } else - lseek(AVI->fdes,n,SEEK_CUR); + if (lseek(AVI->fdes,n,SEEK_CUR)==(off_t)-1) break; } - else if(strncasecmp((char*)data,"idx1",4) == 0) + else if(strncasecmp(data,"idx1",4) == 0) { /* n must be a multiple of 16, but the reading does not break if this is not the case */ AVI->n_idx = AVI->max_idx = n/16; - AVI->idx = (uint8_t((*)[16]) ) malloc(n); + AVI->idx = (unsigned char((*)[16]) ) malloc(n); if(AVI->idx==0) ERR_EXIT(AVI_ERR_NO_MEM) - if( read(AVI->fdes,AVI->idx,n) != n ) ERR_EXIT(AVI_ERR_READ) + if(avi_read(AVI->fdes, (char *) AVI->idx, n) != n ) { + free ( AVI->idx); AVI->idx=NULL; + AVI->n_idx = 0; + } } else lseek(AVI->fdes,n,SEEK_CUR); @@ -738,107 +2348,282 @@ avi_t *AVI_open_input_file(char *filename, int getIndex, int mmap_size) { /* List tags are completly ignored */ - if(strncasecmp((char*)hdrl_data+i,"LIST",4)==0) { i+= 12; continue; } +#ifdef DEBUG_ODML + printf("TAG %c%c%c%c\n", (hdrl_data+i)[0], (hdrl_data+i)[1], (hdrl_data+i)[2], (hdrl_data+i)[3]); +#endif + + if(strncasecmp((char *)hdrl_data+i,"LIST",4)==0) { i+= 12; continue; } n = str2ulong(hdrl_data+i+4); n = PAD_EVEN(n); + /* Interpret the tag and its args */ - if(strncasecmp((char*)hdrl_data+i,"strh",4)==0) + if(strncasecmp((char *)hdrl_data+i,"strh",4)==0) { i += 8; - if(strncasecmp((char*)hdrl_data+i,"vids",4) == 0 && !vids_strh_seen) +#ifdef DEBUG_ODML + printf("TAG %c%c%c%c\n", (hdrl_data+i)[0], (hdrl_data+i)[1], (hdrl_data+i)[2], (hdrl_data+i)[3]); +#endif + if(strncasecmp((char *)hdrl_data+i,"vids",4) == 0 && !vids_strh_seen) { memcpy(AVI->compressor,hdrl_data+i+4,4); AVI->compressor[4] = 0; + + // ThOe + AVI->v_codech_off = header_offset + i+4; + scale = str2ulong(hdrl_data+i+20); rate = str2ulong(hdrl_data+i+24); - if(scale!=0) AVI->fps = (double)rate/(double)(scale); - /* kludge to get ntsc 29.97 correct */ - if (AVI->fps > 29.95 && AVI->fps < 29.99) - AVI->fps = 30000.0/1001.0; /* ntsc frame rate */ + if(scale!=0) AVI->fps = (double)rate/(double)scale; AVI->video_frames = str2ulong(hdrl_data+i+32); AVI->video_strn = num_stream; + AVI->max_len = 0; vids_strh_seen = 1; + AVI->ffmpeg_codec_id = + vj_el_get_decoder_from_fourcc( AVI->compressor ); - veejay_msg(0, "Try '%s'", AVI->compressor ); - - /* setup FFMPEG codec */ - if( strncasecmp("mjpg", AVI->compressor, 4) == 0) - AVI->ffmpeg_codec_id = CODEC_ID_MJPEG; - if( strncasecmp("jpeg", AVI->compressor, 4) == 0) - AVI->ffmpeg_codec_id = CODEC_ID_MJPEG; - if( strncasecmp("mjpa", AVI->compressor, 4) == 0) - AVI->ffmpeg_codec_id = CODEC_ID_MJPEG; - if( strncasecmp("dvsd", AVI->compressor, 4) == 0) - AVI->ffmpeg_codec_id = CODEC_ID_DVVIDEO; - if( strncasecmp("dv", AVI->compressor, 2) == 0) - AVI->ffmpeg_codec_id = CODEC_ID_DVVIDEO; - if( strncasecmp("mp4v",AVI->compressor,4) == 0) - AVI->ffmpeg_codec_id = CODEC_ID_MPEG4; - if( strncasecmp("div3", AVI->compressor,4) == 0) - AVI->ffmpeg_codec_id = CODEC_ID_MSMPEG4V3; - - if( strncasecmp("ljpg", AVI->compressor,4 ) == 0 ) - AVI->ffmpeg_codec_id = CODEC_ID_LJPEG; - if( strncasecmp("hfyu", AVI->compressor,4 ) == 0 ) - AVI->ffmpeg_codec_id = CODEC_ID_HUFFYUV; - - /* non standard follow */ - if( strncasecmp("iyuv", AVI->compressor,4) == 0) - AVI->ffmpeg_codec_id = 997; - if( strncasecmp("i420", AVI->compressor,4) == 0) - AVI->ffmpeg_codec_id = 997; - if( strncasecmp("yv16", AVI->compressor,4) == 0) - AVI->ffmpeg_codec_id = 998; - if( strncasecmp( "i444", AVI->compressor,4) == 0 ) - AVI->ffmpeg_codec_id = 999; - - lasttag = 1; /* vids */ + lasttag = 1; /* vids */ } - else if (strncasecmp ((char*)hdrl_data+i,"auds",4) ==0 && ! auds_strh_seen) + else if (strncasecmp ((char *)hdrl_data+i,"auds",4) ==0 && ! auds_strh_seen) { - AVI->audio_bytes = str2ulong(hdrl_data+i+32)*avi_sampsize(AVI); - AVI->audio_strn = num_stream; - auds_strh_seen = 1; - lasttag = 2; /* auds */ + + //inc audio tracks + AVI->aptr=AVI->anum; + ++AVI->anum; + + if(AVI->anum > AVI_MAX_TRACKS) { + fprintf(stderr, "error - only %d audio tracks supported\n", AVI_MAX_TRACKS); + return(-1); + } + + AVI->track[AVI->aptr].audio_bytes = str2ulong(hdrl_data+i+32)*avi_sampsize(AVI, 0); + AVI->track[AVI->aptr].audio_strn = num_stream; + + // if samplesize==0 -> vbr + AVI->track[AVI->aptr].a_vbr = !str2ulong(hdrl_data+i+44); + + AVI->track[AVI->aptr].padrate = str2ulong(hdrl_data+i+24); + + // auds_strh_seen = 1; + lasttag = 2; /* auds */ + + // ThOe + AVI->track[AVI->aptr].a_codech_off = header_offset + i; + } + else if (strncasecmp (hdrl_data+i,"iavs",4) ==0 && ! auds_strh_seen) { + fprintf(stderr, "AVILIB: error - DV AVI Type 1 no supported\n"); + return (-1); + } else lasttag = 0; num_stream++; } - else if(strncasecmp((char*)hdrl_data+i,"strf",4)==0) + else if(strncasecmp(hdrl_data+i,"dmlh",4) == 0) { + AVI->total_frames = str2ulong(hdrl_data+i+8); +#ifdef DEBUG_ODML + fprintf(stderr, "real number of frames %d\n", AVI->total_frames); +#endif + i += 8; + } + else if(strncasecmp((char *)hdrl_data+i,"strf",4)==0) { i += 8; if(lasttag == 1) { + alBITMAPINFOHEADER bih; + + memcpy(&bih, hdrl_data + i, sizeof(alBITMAPINFOHEADER)); + AVI->bitmap_info_header = (alBITMAPINFOHEADER *) + malloc(str2ulong((unsigned char *)&bih.bi_size)); + if (AVI->bitmap_info_header != NULL) + memcpy(AVI->bitmap_info_header, hdrl_data + i, + str2ulong((unsigned char *)&bih.bi_size)); + AVI->width = str2ulong(hdrl_data+i+4); AVI->height = str2ulong(hdrl_data+i+8); - vids_strf_seen = 1; + vids_strf_seen = 1; + //ThOe + AVI->v_codecf_off = header_offset + i+16; + + memcpy(AVI->compressor2, hdrl_data+i+16, 4); + AVI->compressor2[4] = 0; + } else if(lasttag == 2) { - AVI->a_fmt = str2ushort(hdrl_data+i ); - AVI->a_chans = str2ushort(hdrl_data+i+2); - AVI->a_rate = str2ulong (hdrl_data+i+4); - AVI->a_bits = str2ushort(hdrl_data+i+14); - auds_strf_seen = 1; + alWAVEFORMATEX *wfe; + char *nwfe; + int wfes; + + if ((hdrl_len - i) < sizeof(alWAVEFORMATEX)) + wfes = hdrl_len - i; + else + wfes = sizeof(alWAVEFORMATEX); + wfe = (alWAVEFORMATEX *)malloc(sizeof(alWAVEFORMATEX)); + if (wfe != NULL) { + memset(wfe, 0, sizeof(alWAVEFORMATEX)); + memcpy(wfe, hdrl_data + i, wfes); + if (str2ushort((unsigned char *)&wfe->cb_size) != 0) { + nwfe = (char *) + realloc(wfe, sizeof(alWAVEFORMATEX) + + str2ushort((unsigned char *)&wfe->cb_size)); + if (nwfe != 0) { + off_t lpos = lseek(AVI->fdes, 0, SEEK_CUR); + lseek(AVI->fdes, header_offset + i + sizeof(alWAVEFORMATEX), + SEEK_SET); + wfe = (alWAVEFORMATEX *)nwfe; + nwfe = &nwfe[sizeof(alWAVEFORMATEX)]; + avi_read(AVI->fdes, nwfe, + str2ushort((unsigned char *)&wfe->cb_size)); + lseek(AVI->fdes, lpos, SEEK_SET); + } + } + AVI->wave_format_ex[AVI->aptr] = wfe; + } + + AVI->track[AVI->aptr].a_fmt = str2ushort(hdrl_data+i ); + + //ThOe + AVI->track[AVI->aptr].a_codecf_off = header_offset + i; + + AVI->track[AVI->aptr].a_chans = str2ushort(hdrl_data+i+2); + AVI->track[AVI->aptr].a_rate = str2ulong (hdrl_data+i+4); + //ThOe: read mp3bitrate + AVI->track[AVI->aptr].mp3rate = 8*str2ulong(hdrl_data+i+8)/1000; + //:ThOe + AVI->track[AVI->aptr].a_bits = str2ushort(hdrl_data+i+14); + // auds_strf_seen = 1; } - lasttag = 0; } - else + else if(strncasecmp(hdrl_data+i,"indx",4) == 0) { + char *a; + int j; + + if(lasttag == 1) // V I D E O + { + + a = hdrl_data+i; + + AVI->video_superindex = (avisuperindex_chunk *) malloc (sizeof (avisuperindex_chunk)); + memcpy (AVI->video_superindex->fcc, a, 4); a += 4; + AVI->video_superindex->dwSize = str2ulong(a); a += 4; + AVI->video_superindex->wLongsPerEntry = str2ushort(a); a += 2; + AVI->video_superindex->bIndexSubType = *a; a += 1; + AVI->video_superindex->bIndexType = *a; a += 1; + AVI->video_superindex->nEntriesInUse = str2ulong(a); a += 4; + memcpy (AVI->video_superindex->dwChunkId, a, 4); a += 4; + + // 3 * reserved + a += 4; a += 4; a += 4; + + if (AVI->video_superindex->bIndexSubType != 0) {fprintf(stderr, "Invalid Header, bIndexSubType != 0\n"); } + + AVI->video_superindex->aIndex = + malloc (AVI->video_superindex->wLongsPerEntry * AVI->video_superindex->nEntriesInUse * sizeof (uint32_t)); + + // position of ix## chunks + for (j=0; jvideo_superindex->nEntriesInUse; ++j) { + AVI->video_superindex->aIndex[j].qwOffset = str2ullong (a); a += 8; + AVI->video_superindex->aIndex[j].dwSize = str2ulong (a); a += 4; + AVI->video_superindex->aIndex[j].dwDuration = str2ulong (a); a += 4; + +#ifdef DEBUG_ODML + printf("[%d] 0x%llx 0x%lx %lu\n", j, + (unsigned long long)AVI->video_superindex->aIndex[j].qwOffset, + (unsigned long)AVI->video_superindex->aIndex[j].dwSize, + (unsigned long)AVI->video_superindex->aIndex[j].dwDuration); +#endif + } + + +#ifdef DEBUG_ODML + printf("FOURCC \"%c%c%c%c\"\n", AVI->video_superindex->fcc[0], AVI->video_superindex->fcc[1], + AVI->video_superindex->fcc[2], AVI->video_superindex->fcc[3]); + printf("LEN \"%ld\"\n", (long)AVI->video_superindex->dwSize); + printf("wLongsPerEntry \"%d\"\n", AVI->video_superindex->wLongsPerEntry); + printf("bIndexSubType \"%d\"\n", AVI->video_superindex->bIndexSubType); + printf("bIndexType \"%d\"\n", AVI->video_superindex->bIndexType); + printf("nEntriesInUse \"%ld\"\n", (long)AVI->video_superindex->nEntriesInUse); + printf("dwChunkId \"%c%c%c%c\"\n", AVI->video_superindex->dwChunkId[0], AVI->video_superindex->dwChunkId[1], + AVI->video_superindex->dwChunkId[2], AVI->video_superindex->dwChunkId[3]); + printf("--\n"); +#endif + + AVI->is_opendml = 1; + + } + else if(lasttag == 2) // A U D I O + { + + a = hdrl_data+i; + + AVI->track[AVI->aptr].audio_superindex = (avisuperindex_chunk *) malloc (sizeof (avisuperindex_chunk)); + memcpy (AVI->track[AVI->aptr].audio_superindex->fcc, a, 4); a += 4; + AVI->track[AVI->aptr].audio_superindex->dwSize = str2ulong(a); a += 4; + AVI->track[AVI->aptr].audio_superindex->wLongsPerEntry = str2ushort(a); a += 2; + AVI->track[AVI->aptr].audio_superindex->bIndexSubType = *a; a += 1; + AVI->track[AVI->aptr].audio_superindex->bIndexType = *a; a += 1; + AVI->track[AVI->aptr].audio_superindex->nEntriesInUse = str2ulong(a); a += 4; + memcpy (AVI->track[AVI->aptr].audio_superindex->dwChunkId, a, 4); a += 4; + + // 3 * reserved + a += 4; a += 4; a += 4; + + if (AVI->track[AVI->aptr].audio_superindex->bIndexSubType != 0) {fprintf(stderr, "Invalid Header, bIndexSubType != 0\n"); } + + AVI->track[AVI->aptr].audio_superindex->aIndex = + malloc (AVI->track[AVI->aptr].audio_superindex->wLongsPerEntry * + AVI->track[AVI->aptr].audio_superindex->nEntriesInUse * sizeof (uint32_t)); + + // position of ix## chunks + for (j=0; jtrack[AVI->aptr].audio_superindex->nEntriesInUse; ++j) { + AVI->track[AVI->aptr].audio_superindex->aIndex[j].qwOffset = str2ullong (a); a += 8; + AVI->track[AVI->aptr].audio_superindex->aIndex[j].dwSize = str2ulong (a); a += 4; + AVI->track[AVI->aptr].audio_superindex->aIndex[j].dwDuration = str2ulong (a); a += 4; + +#ifdef DEBUG_ODML + printf("[%d] 0x%llx 0x%lx %lu\n", j, + (unsigned long long)AVI->track[AVI->aptr].audio_superindex->aIndex[j].qwOffset, + (unsigned long)AVI->track[AVI->aptr].audio_superindex->aIndex[j].dwSize, + (unsigned long)AVI->track[AVI->aptr].audio_superindex->aIndex[j].dwDuration); +#endif + } + +#ifdef DEBUG_ODML + printf("FOURCC \"%.4s\"\n", AVI->track[AVI->aptr].audio_superindex->fcc); + printf("LEN \"%ld\"\n", (long)AVI->track[AVI->aptr].audio_superindex->dwSize); + printf("wLongsPerEntry \"%d\"\n", AVI->track[AVI->aptr].audio_superindex->wLongsPerEntry); + printf("bIndexSubType \"%d\"\n", AVI->track[AVI->aptr].audio_superindex->bIndexSubType); + printf("bIndexType \"%d\"\n", AVI->track[AVI->aptr].audio_superindex->bIndexType); + printf("nEntriesInUse \"%ld\"\n", (long)AVI->track[AVI->aptr].audio_superindex->nEntriesInUse); + printf("dwChunkId \"%.4s\"\n", AVI->track[AVI->aptr].audio_superindex->dwChunkId[0]); + printf("--\n"); +#endif + + } + i += 8; + } + else if((strncasecmp(hdrl_data+i,"JUNK",4) == 0) || + (strncasecmp(hdrl_data+i,"strn",4) == 0) || + (strncasecmp(hdrl_data+i,"vprp",4) == 0)){ + i += 8; + // do not reset lasttag + } else { i += 8; lasttag = 0; } + //printf("adding %ld bytes\n", (long int)n); i += n; } free(hdrl_data); - if(!vids_strh_seen || !vids_strf_seen || AVI->video_frames==0) ERR_EXIT(AVI_ERR_NO_VIDS) + if(!vids_strh_seen || !vids_strf_seen) ERR_EXIT(AVI_ERR_NO_VIDS) AVI->video_tag[0] = AVI->video_strn/10 + '0'; AVI->video_tag[1] = AVI->video_strn%10 + '0'; @@ -846,18 +2631,37 @@ avi_t *AVI_open_input_file(char *filename, int getIndex, int mmap_size) AVI->video_tag[3] = 'b'; /* Audio tag is set to "99wb" if no audio present */ - if(!AVI->a_chans) AVI->audio_strn = 99; + if(!AVI->track[0].a_chans) AVI->track[0].audio_strn = 99; - AVI->audio_tag[0] = AVI->audio_strn/10 + '0'; - AVI->audio_tag[1] = AVI->audio_strn%10 + '0'; - AVI->audio_tag[2] = 'w'; - AVI->audio_tag[3] = 'b'; + { + int i=0; + for(j=0; janum+1; ++j) { + if (j == AVI->video_strn) continue; + AVI->track[i].audio_tag[0] = j/10 + '0'; + AVI->track[i].audio_tag[1] = j%10 + '0'; + AVI->track[i].audio_tag[2] = 'w'; + AVI->track[i].audio_tag[3] = 'b'; + ++i; + } + } lseek(AVI->fdes,AVI->movi_start,SEEK_SET); /* get index if wanted */ - if(!getIndex) return AVI; + if(AVI->index_file && !getIndex) { + int ret; + + ret = avi_parse_index_from_file(AVI, AVI->index_file); + + /* Reposition the file */ + + lseek(AVI->fdes,AVI->movi_start,SEEK_SET); + AVI->video_pos = 0; + return (ret); + + } + if(!getIndex) return(0); /* if the file has an idx1, check if this is relative to the start of the file or to the start of the movi list */ @@ -866,29 +2670,29 @@ avi_t *AVI_open_input_file(char *filename, int getIndex, int mmap_size) if(AVI->idx) { - long pos, len; + off_t pos, len; /* Search the first videoframe in the idx1 and look where it is in the file */ for(i=0;in_idx;i++) - if( strncasecmp((char*)AVI->idx[i],(char*)AVI->video_tag,3)==0 ) break; + if( strncasecmp((char *)AVI->idx[i],(char *)AVI->video_tag,3)==0 ) break; if(i>=AVI->n_idx) ERR_EXIT(AVI_ERR_NO_VIDS) pos = str2ulong(AVI->idx[i]+ 8); len = str2ulong(AVI->idx[i]+12); lseek(AVI->fdes,pos,SEEK_SET); - if(read(AVI->fdes,data,8)!=8) ERR_EXIT(AVI_ERR_READ) - if( strncasecmp((char*)data,(char*)AVI->idx[i],4)==0 && str2ulong(data+4)==len ) + if(avi_read(AVI->fdes,data,8)!=8) ERR_EXIT(AVI_ERR_READ) + if( strncasecmp(data,(char *)AVI->idx[i],4)==0 && str2ulong((unsigned char *)data+4)==len ) { idx_type = 1; /* Index from start of file */ } else { lseek(AVI->fdes,pos+AVI->movi_start-4,SEEK_SET); - if(read(AVI->fdes,data,8)!=8) ERR_EXIT(AVI_ERR_READ) - if( strncasecmp((char*)data,(char*)AVI->idx[i],4)==0 && str2ulong(data+4)==len ) + if(avi_read(AVI->fdes,data,8)!=8) ERR_EXIT(AVI_ERR_READ) + if( strncasecmp(data,(char *)AVI->idx[i],4)==0 && str2ulong((unsigned char *)data+4)==len ) { idx_type = 2; /* Index from start of movi list */ } @@ -896,106 +2700,390 @@ avi_t *AVI_open_input_file(char *filename, int getIndex, int mmap_size) /* idx_type remains 0 if neither of the two tests above succeeds */ } - if(idx_type == 0) + + if(idx_type == 0 && !AVI->is_opendml && !AVI->total_frames) { /* we must search through the file to get the index */ lseek(AVI->fdes, AVI->movi_start, SEEK_SET); + AVI->n_idx = 0; while(1) { - if( read(AVI->fdes,data,8) != 8 ) break; - n = str2ulong(data+4); + if( avi_read(AVI->fdes,data,8) != 8 ) break; + n = str2ulong((unsigned char *)data+4); /* The movi list may contain sub-lists, ignore them */ - if(strncasecmp((char*)data,"LIST",4)==0) + if(strncasecmp(data,"LIST",4)==0) { lseek(AVI->fdes,4,SEEK_CUR); continue; } /* Check if we got a tag ##db, ##dc or ##wb */ - + if( ( (data[2]=='d' || data[2]=='D') && (data[3]=='b' || data[3]=='B' || data[3]=='c' || data[3]=='C') ) - || ( (data[2]=='w' || data[2]=='W') && - (data[3]=='b' || data[3]=='B') ) ) - { - avi_add_index_entry(AVI,data,0,lseek(AVI->fdes,0,SEEK_CUR)-8,n); + || ( (data[2]=='w' || data[2]=='W') && + (data[3]=='b' || data[3]=='B') ) ) + { + avi_add_index_entry(AVI,(unsigned char *)data,0,lseek(AVI->fdes,0,SEEK_CUR)-8,n); } - + lseek(AVI->fdes,PAD_EVEN(n),SEEK_CUR); } idx_type = 1; } + // ************************ + // OPENDML + // ************************ + + // read extended index chunks + if (AVI->is_opendml) { + uint64_t offset = 0; + int hdrl_len = 4+4+2+1+1+4+4+8+4; + char *en, *chunk_start; + int k = 0, audtr = 0; + uint32_t nrEntries = 0; + + AVI->video_index = NULL; + + nvi = 0; + for(audtr=0; audtranum; ++audtr) nai[audtr] = tot[audtr] = 0; + + // ************************ + // VIDEO + // ************************ + + for (j=0; jvideo_superindex->nEntriesInUse; j++) { + + // read from file + chunk_start = en = malloc (AVI->video_superindex->aIndex[j].dwSize+hdrl_len); + + if (lseek(AVI->fdes, AVI->video_superindex->aIndex[j].qwOffset, SEEK_SET) == (off_t)-1) { + fprintf(stderr, "(%s) cannot seek to 0x%llx\n", __FILE__, + (unsigned long long)AVI->video_superindex->aIndex[j].qwOffset); + free(chunk_start); + continue; + } + + if (avi_read(AVI->fdes, en, AVI->video_superindex->aIndex[j].dwSize+hdrl_len) <= 0) { + fprintf(stderr, "(%s) cannot read from offset 0x%llx %ld bytes; broken (incomplete) file?\n", + __FILE__, (unsigned long long)AVI->video_superindex->aIndex[j].qwOffset, + (unsigned long)AVI->video_superindex->aIndex[j].dwSize+hdrl_len); + free(chunk_start); + continue; + } + + nrEntries = str2ulong(en + 12); +#ifdef DEBUG_ODML + //printf("[%d:0] Video nrEntries %ld\n", j, nrEntries); +#endif + offset = str2ullong(en + 20); + + // skip header + en += hdrl_len; + nvi += nrEntries; + AVI->video_index = (video_index_entry *) realloc (AVI->video_index, nvi * sizeof (video_index_entry)); + if (!AVI->video_index) { + fprintf(stderr, "AVILIB: out of mem (size = %ld)\n", nvi * sizeof (video_index_entry)); + exit(1); + } + + while (k < nvi) { + + AVI->video_index[k].pos = offset + str2ulong(en); en += 4; + AVI->video_index[k].len = str2ulong_len(en); + AVI->video_index[k].key = str2ulong_key(en); en += 4; + + // completely empty chunk + if (AVI->video_index[k].pos-offset == 0 && AVI->video_index[k].len == 0) { + k--; + nvi--; + } + +#ifdef DEBUG_ODML + /* + printf("[%d] POS 0x%llX len=%d key=%s offset (%llx) (%ld)\n", k, + AVI->video_index[k].pos, + (int)AVI->video_index[k].len, + AVI->video_index[k].key?"yes":"no ", offset, + AVI->video_superindex->aIndex[j].dwSize); + */ +#endif + + k++; + } + + free(chunk_start); + } + + AVI->video_frames = nvi; + // this should deal with broken 'rec ' odml files. + if (AVI->video_frames == 0) { + AVI->is_opendml=0; + goto multiple_riff; + } + + // ************************ + // AUDIO + // ************************ + + for(audtr=0; audtranum; ++audtr) { + + k = 0; + if (!AVI->track[audtr].audio_superindex) { + fprintf(stderr, "(%s) cannot read audio index for track %d\n", __FILE__, audtr); + continue; + } + for (j=0; jtrack[audtr].audio_superindex->nEntriesInUse; j++) { + + // read from file + chunk_start = en = malloc (AVI->track[audtr].audio_superindex->aIndex[j].dwSize+hdrl_len); + + if (lseek(AVI->fdes, AVI->track[audtr].audio_superindex->aIndex[j].qwOffset, SEEK_SET) == (off_t)-1) { + fprintf(stderr, "(%s) cannot seek to 0x%llx\n", __FILE__, (unsigned long long)AVI->track[audtr].audio_superindex->aIndex[j].qwOffset); + free(chunk_start); + continue; + } + + if (avi_read(AVI->fdes, en, AVI->track[audtr].audio_superindex->aIndex[j].dwSize+hdrl_len) <= 0) { + fprintf(stderr, "(%s) cannot read from offset 0x%llx; broken (incomplete) file?\n", + __FILE__,(unsigned long long) AVI->track[audtr].audio_superindex->aIndex[j].qwOffset); + free(chunk_start); + continue; + } + + nrEntries = str2ulong(en + 12); + //if (nrEntries > 50) nrEntries = 2; // XXX +#ifdef DEBUG_ODML + //printf("[%d:%d] Audio nrEntries %ld\n", j, audtr, nrEntries); +#endif + offset = str2ullong(en + 20); + + // skip header + en += hdrl_len; + nai[audtr] += nrEntries; + AVI->track[audtr].audio_index = (audio_index_entry *) realloc (AVI->track[audtr].audio_index, nai[audtr] * sizeof (audio_index_entry)); + + while (k < nai[audtr]) { + + AVI->track[audtr].audio_index[k].pos = offset + str2ulong(en); en += 4; + AVI->track[audtr].audio_index[k].len = str2ulong_len(en); en += 4; + AVI->track[audtr].audio_index[k].tot = tot[audtr]; + tot[audtr] += AVI->track[audtr].audio_index[k].len; + +#ifdef DEBUG_ODML + /* + printf("[%d:%d] POS 0x%llX len=%d offset (%llx) (%ld)\n", k, audtr, + AVI->track[audtr].audio_index[k].pos, + (int)AVI->track[audtr].audio_index[k].len, + offset, AVI->track[audtr].audio_superindex->aIndex[j].dwSize); + */ +#endif + + ++k; + } + + free(chunk_start); + } + + AVI->track[audtr].audio_chunks = nai[audtr]; + AVI->track[audtr].audio_bytes = tot[audtr]; + } + } // is opendml + + else if (AVI->total_frames && !AVI->is_opendml && idx_type==0) { + + // ********************* + // MULTIPLE RIFF CHUNKS (and no index) + // ********************* + + long aud_chunks = 0; +multiple_riff: + + lseek(AVI->fdes, AVI->movi_start, SEEK_SET); + + AVI->n_idx = 0; + + fprintf(stderr, "[avilib] Reconstructing index..."); + + // Number of frames; only one audio track supported + nvi = AVI->video_frames = AVI->total_frames; + nai[0] = AVI->track[0].audio_chunks = AVI->total_frames; + for(j=1; janum; ++j) AVI->track[j].audio_chunks = 0; + + AVI->video_index = (video_index_entry *) malloc(nvi*sizeof(video_index_entry)); + + if(AVI->video_index==0) ERR_EXIT(AVI_ERR_NO_MEM); + + for(j=0; janum; ++j) { + if(AVI->track[j].audio_chunks) { + AVI->track[j].audio_index = (audio_index_entry *) malloc((nai[j]+1)*sizeof(audio_index_entry)); + memset(AVI->track[j].audio_index, 0, (nai[j]+1)*(sizeof(audio_index_entry))); + if(AVI->track[j].audio_index==0) ERR_EXIT(AVI_ERR_NO_MEM); + } + } + + nvi = 0; + for(j=0; janum; ++j) nai[j] = tot[j] = 0; + + aud_chunks = AVI->total_frames; + + while(1) + { + if (nvi >= AVI->total_frames) break; + + if( avi_read(AVI->fdes,data,8) != 8 ) break; + n = str2ulong((unsigned char *)data+4); + + + j=0; + + if (aud_chunks - nai[j] -1 <= 0) { + aud_chunks += AVI->total_frames; + AVI->track[j].audio_index = (audio_index_entry *) + realloc( AVI->track[j].audio_index, (aud_chunks+1)*sizeof(audio_index_entry)); + if (!AVI->track[j].audio_index) { + fprintf(stderr, "Internal error in avilib -- no mem\n"); + AVI_errno = AVI_ERR_NO_MEM; + return -1; + } + } + + /* Check if we got a tag ##db, ##dc or ##wb */ + + // VIDEO + if( + (data[0]=='0' || data[1]=='0') && + (data[2]=='d' || data[2]=='D') && + (data[3]=='b' || data[3]=='B' || data[3]=='c' || data[3]=='C') ) { + + AVI->video_index[nvi].key = 0x0; + AVI->video_index[nvi].pos = lseek(AVI->fdes,0,SEEK_CUR); + AVI->video_index[nvi].len = n; + + /* + fprintf(stderr, "Frame %ld pos %lld len %lld key %ld\n", + nvi, AVI->video_index[nvi].pos, AVI->video_index[nvi].len, (long)AVI->video_index[nvi].key); + */ + nvi++; + lseek(AVI->fdes,PAD_EVEN(n),SEEK_CUR); + } + + //AUDIO + else if( + (data[0]=='0' || data[1]=='1') && + (data[2]=='w' || data[2]=='W') && + (data[3]=='b' || data[3]=='B') ) { + + + AVI->track[j].audio_index[nai[j]].pos = lseek(AVI->fdes,0,SEEK_CUR); + AVI->track[j].audio_index[nai[j]].len = n; + AVI->track[j].audio_index[nai[j]].tot = tot[j]; + tot[j] += AVI->track[j].audio_index[nai[j]].len; + nai[j]++; + + lseek(AVI->fdes,PAD_EVEN(n),SEEK_CUR); + } + else { + lseek(AVI->fdes,-4,SEEK_CUR); + } + + } + if (nvi < AVI->total_frames) { + fprintf(stderr, "\n[avilib] Uh? Some frames seems missing (%ld/%d)\n", + nvi, AVI->total_frames); + } + + + AVI->video_frames = nvi; + AVI->track[0].audio_chunks = nai[0]; + + for(j=0; janum; ++j) AVI->track[j].audio_bytes = tot[j]; + idx_type = 1; + fprintf(stderr, "done. nvi=%ld nai=%ld tot=%ld\n", nvi, nai[0], tot[0]); + + } // total_frames but no indx chunk (xawtv does this) + + else + + { + // ****************** + // NO OPENDML + // ****************** + /* Now generate the video index and audio index arrays */ nvi = 0; - nai = 0; + for(j=0; janum; ++j) nai[j] = 0; - for(i=0;in_idx;i++) - { - if(strncasecmp((char*)AVI->idx[i],(char*)AVI->video_tag,3) == 0) nvi++; - if(strncasecmp((char*)AVI->idx[i],(char*)AVI->audio_tag,4) == 0) nai++; + for(i=0;in_idx;i++) { + + if(strncasecmp((char *)AVI->idx[i],AVI->video_tag,3) == 0) nvi++; + + for(j=0; janum; ++j) if(strncasecmp((char *)AVI->idx[i], AVI->track[j].audio_tag,4) == 0) nai[j]++; } - + AVI->video_frames = nvi; - AVI->audio_chunks = nai; + for(j=0; janum; ++j) AVI->track[j].audio_chunks = nai[j]; + - if(AVI->video_frames==0) ERR_EXIT(AVI_ERR_NO_VIDS) + if(AVI->video_frames==0) ERR_EXIT(AVI_ERR_NO_VIDS); AVI->video_index = (video_index_entry *) malloc(nvi*sizeof(video_index_entry)); - if(AVI->video_index==0) ERR_EXIT(AVI_ERR_NO_MEM) - if(AVI->audio_chunks) - { - AVI->audio_index = (audio_index_entry *) malloc(nai*sizeof(audio_index_entry)); - if(AVI->audio_index==0) ERR_EXIT(AVI_ERR_NO_MEM) - } - + if(AVI->video_index==0) ERR_EXIT(AVI_ERR_NO_MEM); + + for(j=0; janum; ++j) { + if(AVI->track[j].audio_chunks) { + AVI->track[j].audio_index = (audio_index_entry *) malloc((nai[j]+1)*sizeof(audio_index_entry)); + memset(AVI->track[j].audio_index, 0, (nai[j]+1)*(sizeof(audio_index_entry))); + if(AVI->track[j].audio_index==0) ERR_EXIT(AVI_ERR_NO_MEM); + } + } + nvi = 0; - nai = 0; - tot = 0; + for(j=0; janum; ++j) nai[j] = tot[j] = 0; + ioff = idx_type == 1 ? 8 : AVI->movi_start+4; + + for(i=0;in_idx;i++) { - for(i=0;in_idx;i++) - { - if(strncasecmp((char*)AVI->idx[i],(char*)AVI->video_tag,3) == 0) - { - AVI->video_index[nvi].pos = str2ulong(AVI->idx[i]+ 8)+ioff; - AVI->video_index[nvi].len = str2ulong(AVI->idx[i]+12); - nvi++; - } - if(strncasecmp((char*)AVI->idx[i],(char*)AVI->audio_tag,4) == 0) - { - AVI->audio_index[nai].pos = str2ulong(AVI->idx[i]+ 8)+ioff; - AVI->audio_index[nai].len = str2ulong(AVI->idx[i]+12); - AVI->audio_index[nai].tot = tot; - tot += AVI->audio_index[nai].len; - nai++; - } + //video + if(strncasecmp((char *)AVI->idx[i],AVI->video_tag,3) == 0) { + AVI->video_index[nvi].key = str2ulong(AVI->idx[i]+ 4); + AVI->video_index[nvi].pos = str2ulong(AVI->idx[i]+ 8)+ioff; + AVI->video_index[nvi].len = str2ulong(AVI->idx[i]+12); + nvi++; + } + + //audio + for(j=0; janum; ++j) { + + if(strncasecmp((char *)AVI->idx[i],AVI->track[j].audio_tag,4) == 0) { + AVI->track[j].audio_index[nai[j]].pos = str2ulong(AVI->idx[i]+ 8)+ioff; + AVI->track[j].audio_index[nai[j]].len = str2ulong(AVI->idx[i]+12); + AVI->track[j].audio_index[nai[j]].tot = tot[j]; + tot[j] += AVI->track[j].audio_index[nai[j]].len; + nai[j]++; + } + } } + + + for(j=0; janum; ++j) AVI->track[j].audio_bytes = tot[j]; - AVI->audio_bytes = tot; - - long file_size = 0; - file_size = (long) lseek( AVI->fdes, 0, SEEK_END ); + } // is no opendml /* Reposition the file */ + lseek(AVI->fdes,AVI->movi_start,SEEK_SET); AVI->video_pos = 0; - /* map file to memory */ - AVI->mmap_region = NULL; - AVI->mmap_size = AVI->width * AVI->height * mmap_size; - if(AVI->mmap_size > 0) - { - AVI->mmap_region = mmap_file( AVI->fdes, 0, AVI->mmap_size, file_size ); - } - - return AVI; + return(0); } long AVI_video_frames(avi_t *AVI) @@ -1016,33 +3104,77 @@ double AVI_frame_rate(avi_t *AVI) } char* AVI_video_compressor(avi_t *AVI) { - return AVI->compressor; -} -int AVI_video_compressor_type(avi_t *AVI) -{ - return AVI->ffmpeg_codec_id; + return AVI->compressor2; } +long AVI_max_video_chunk(avi_t *AVI) +{ + return AVI->max_len; +} + +int AVI_audio_tracks(avi_t *AVI) +{ + return(AVI->anum); +} int AVI_audio_channels(avi_t *AVI) { - return AVI->a_chans; + return AVI->track[AVI->aptr].a_chans; } + +long AVI_audio_mp3rate(avi_t *AVI) +{ + return AVI->track[AVI->aptr].mp3rate; +} + +long AVI_audio_padrate(avi_t *AVI) +{ + return AVI->track[AVI->aptr].padrate; +} + int AVI_audio_bits(avi_t *AVI) { - return AVI->a_bits; + return AVI->track[AVI->aptr].a_bits; } + int AVI_audio_format(avi_t *AVI) { - return AVI->a_fmt; + return AVI->track[AVI->aptr].a_fmt; } + long AVI_audio_rate(avi_t *AVI) { - return AVI->a_rate; + return AVI->track[AVI->aptr].a_rate; } + long AVI_audio_bytes(avi_t *AVI) { - return AVI->audio_bytes; + return AVI->track[AVI->aptr].audio_bytes; +} + +long AVI_audio_chunks(avi_t *AVI) +{ + return AVI->track[AVI->aptr].audio_chunks; +} + +long AVI_audio_codech_offset(avi_t *AVI) +{ + return AVI->track[AVI->aptr].a_codech_off; +} + +long AVI_audio_codecf_offset(avi_t *AVI) +{ + return AVI->track[AVI->aptr].a_codecf_off; +} + +long AVI_video_codech_offset(avi_t *AVI) +{ + return AVI->v_codech_off; +} + +long AVI_video_codecf_offset(avi_t *AVI) +{ + return AVI->v_codecf_off; } long AVI_frame_size(avi_t *AVI, long frame) @@ -1054,6 +3186,25 @@ long AVI_frame_size(avi_t *AVI, long frame) return(AVI->video_index[frame].len); } +long AVI_audio_size(avi_t *AVI, long frame) +{ + if(AVI->mode==AVI_MODE_WRITE) { AVI_errno = AVI_ERR_NOT_PERM; return -1; } + if(!AVI->track[AVI->aptr].audio_index) { AVI_errno = AVI_ERR_NO_IDX; return -1; } + + if(frame < 0 || frame >= AVI->track[AVI->aptr].audio_chunks) return -1; + return(AVI->track[AVI->aptr].audio_index[frame].len); +} + +long AVI_get_video_position(avi_t *AVI, long frame) +{ + if(AVI->mode==AVI_MODE_WRITE) { AVI_errno = AVI_ERR_NOT_PERM; return -1; } + if(!AVI->video_index) { AVI_errno = AVI_ERR_NO_IDX; return -1; } + + if(frame < 0 || frame >= AVI->video_frames) return 0; + return(AVI->video_index[frame].pos); +} + + int AVI_seek_start(avi_t *AVI) { if(AVI->mode==AVI_MODE_WRITE) { AVI_errno = AVI_ERR_NOT_PERM; return -1; } @@ -1072,110 +3223,188 @@ int AVI_set_video_position(avi_t *AVI, long frame) AVI->video_pos = frame; return 0; } + +int AVI_set_audio_bitrate(avi_t *AVI, long bitrate) +{ + if(AVI->mode==AVI_MODE_READ) { AVI_errno = AVI_ERR_NOT_PERM; return -1; } + + AVI->track[AVI->aptr].mp3rate = bitrate; + return 0; +} -long AVI_read_frame(avi_t *AVI, uint8_t *vidbuf) +long AVI_read_frame(avi_t *AVI, char *vidbuf, int *keyframe) { long n; if(AVI->mode==AVI_MODE_WRITE) { AVI_errno = AVI_ERR_NOT_PERM; return -1; } if(!AVI->video_index) { AVI_errno = AVI_ERR_NO_IDX; return -1; } - if(AVI->video_pos < 0 || AVI->video_pos >= AVI->video_frames) return 0; + if(AVI->video_pos < 0 || AVI->video_pos >= AVI->video_frames) return -1; + n = AVI->video_index[AVI->video_pos].len; - n = AVI->video_index[AVI->video_pos].len; - if( AVI->mmap_region == NULL ) - { - lseek(AVI->fdes, AVI->video_index[AVI->video_pos].pos, SEEK_SET); - if (read(AVI->fdes,vidbuf,n) != n) - { - AVI_errno = AVI_ERR_READ; - return -1; + *keyframe = (AVI->video_index[AVI->video_pos].key==0x10) ? 1:0; + + if (vidbuf == NULL) { + AVI->video_pos++; + return n; + } + + if( AVI->mmap_region == NULL ) + { + lseek(AVI->fdes, AVI->video_index[AVI->video_pos].pos, SEEK_SET); + if (avi_read(AVI->fdes,vidbuf,n) != n) + { + AVI_errno = AVI_ERR_READ; + return -1; + } } - } else { - n = mmap_read( AVI->mmap_region, AVI->video_index[AVI->video_pos].pos, - n, vidbuf ); + n = mmap_read( AVI->mmap_region, AVI->video_index[ AVI->video_pos].pos, + n, vidbuf ); } + AVI->video_pos++; return n; } +long AVI_get_audio_position_index(avi_t *AVI) +{ + if(AVI->mode==AVI_MODE_WRITE) { AVI_errno = AVI_ERR_NOT_PERM; return -1; } + if(!AVI->track[AVI->aptr].audio_index) { AVI_errno = AVI_ERR_NO_IDX; return -1; } + + return (AVI->track[AVI->aptr].audio_posc); +} + +int AVI_set_audio_position_index(avi_t *AVI, long indexpos) +{ + if(AVI->mode==AVI_MODE_WRITE) { AVI_errno = AVI_ERR_NOT_PERM; return -1; } + if(!AVI->track[AVI->aptr].audio_index) { AVI_errno = AVI_ERR_NO_IDX; return -1; } + if(indexpos > AVI->track[AVI->aptr].audio_chunks) { AVI_errno = AVI_ERR_NO_IDX; return -1; } + + AVI->track[AVI->aptr].audio_posc = indexpos; + AVI->track[AVI->aptr].audio_posb = 0; + + return 0; +} + + int AVI_set_audio_position(avi_t *AVI, long byte) { long n0, n1, n; if(AVI->mode==AVI_MODE_WRITE) { AVI_errno = AVI_ERR_NOT_PERM; return -1; } - if(!AVI->audio_index) { AVI_errno = AVI_ERR_NO_IDX; return -1; } + if(!AVI->track[AVI->aptr].audio_index) { AVI_errno = AVI_ERR_NO_IDX; return -1; } if(byte < 0) byte = 0; /* Binary search in the audio chunks */ n0 = 0; - n1 = AVI->audio_chunks; + n1 = AVI->track[AVI->aptr].audio_chunks; while(n0audio_index[n].tot>byte) + if(AVI->track[AVI->aptr].audio_index[n].tot>byte) n1 = n; else n0 = n; } - AVI->audio_posc = n0; - AVI->audio_posb = byte - AVI->audio_index[n0].tot; + AVI->track[AVI->aptr].audio_posc = n0; + AVI->track[AVI->aptr].audio_posb = byte - AVI->track[AVI->aptr].audio_index[n0].tot; return 0; } -long AVI_read_audio(avi_t *AVI, uint8_t *audbuf, long bytes) +long AVI_read_audio(avi_t *AVI, char *audbuf, long bytes) { - long nr, pos, left, todo; + long nr, left, todo; + off_t pos; if(AVI->mode==AVI_MODE_WRITE) { AVI_errno = AVI_ERR_NOT_PERM; return -1; } - if(!AVI->audio_index) { AVI_errno = AVI_ERR_NO_IDX; return -1; } + if(!AVI->track[AVI->aptr].audio_index) { AVI_errno = AVI_ERR_NO_IDX; return -1; } nr = 0; /* total number of bytes read */ + if (bytes==0) { + AVI->track[AVI->aptr].audio_posc++; + AVI->track[AVI->aptr].audio_posb = 0; + lseek(AVI->fdes, 0LL, SEEK_CUR); + } while(bytes>0) { - left = AVI->audio_index[AVI->audio_posc].len - AVI->audio_posb; + off_t ret; + left = AVI->track[AVI->aptr].audio_index[AVI->track[AVI->aptr].audio_posc].len - AVI->track[AVI->aptr].audio_posb; if(left==0) { - if(AVI->audio_posc>=AVI->audio_chunks-1) return nr; - AVI->audio_posc++; - AVI->audio_posb = 0; + if(AVI->track[AVI->aptr].audio_posc>=AVI->track[AVI->aptr].audio_chunks-1) return nr; + AVI->track[AVI->aptr].audio_posc++; + AVI->track[AVI->aptr].audio_posb = 0; continue; } if(bytesaudio_index[AVI->audio_posc].pos + AVI->audio_posb; + pos = AVI->track[AVI->aptr].audio_index[AVI->track[AVI->aptr].audio_posc].pos + AVI->track[AVI->aptr].audio_posb; lseek(AVI->fdes, pos, SEEK_SET); - if (read(AVI->fdes,audbuf+nr,todo) != todo) + if ( (ret = avi_read(AVI->fdes,audbuf+nr,todo)) != todo) { + fprintf(stderr, "XXX pos = %lld, ret = %lld, todo = %ld\n", pos, ret, todo); AVI_errno = AVI_ERR_READ; return -1; } bytes -= todo; nr += todo; - AVI->audio_posb += todo; + AVI->track[AVI->aptr].audio_posb += todo; } return nr; } +long AVI_read_audio_chunk(avi_t *AVI, char *audbuf) +{ + long left; + off_t pos; + + if(AVI->mode==AVI_MODE_WRITE) { AVI_errno = AVI_ERR_NOT_PERM; return -1; } + if(!AVI->track[AVI->aptr].audio_index) { AVI_errno = AVI_ERR_NO_IDX; return -1; } + + if (AVI->track[AVI->aptr].audio_posc+1>AVI->track[AVI->aptr].audio_chunks) return -1; + + left = AVI->track[AVI->aptr].audio_index[AVI->track[AVI->aptr].audio_posc].len - AVI->track[AVI->aptr].audio_posb; + + if (audbuf == NULL) return left; + + if(left==0) { + AVI->track[AVI->aptr].audio_posc++; + AVI->track[AVI->aptr].audio_posb = 0; + return 0; + } + + pos = AVI->track[AVI->aptr].audio_index[AVI->track[AVI->aptr].audio_posc].pos + AVI->track[AVI->aptr].audio_posb; + lseek(AVI->fdes, pos, SEEK_SET); + if (avi_read(AVI->fdes,audbuf,left) != left) + { + AVI_errno = AVI_ERR_READ; + return -1; + } + AVI->track[AVI->aptr].audio_posc++; + AVI->track[AVI->aptr].audio_posb = 0; + + return left; +} + /* AVI_read_data: Special routine for reading the next audio or video chunk without having an index of the file. */ -int AVI_read_data(avi_t *AVI, uint8_t *vidbuf, long max_vidbuf, - uint8_t *audbuf, long max_audbuf, +int AVI_read_data(avi_t *AVI, char *vidbuf, long max_vidbuf, + char *audbuf, long max_audbuf, long *len) { @@ -1189,28 +3418,28 @@ int AVI_read_data(avi_t *AVI, uint8_t *vidbuf, long max_vidbuf, * -2 = audio buffer too small */ - int n; - uint8_t data[8]; - + off_t n; + char data[8]; + if(AVI->mode==AVI_MODE_WRITE) return 0; while(1) { /* Read tag and length */ - if( read(AVI->fdes,data,8) != 8 ) return 0; + if( avi_read(AVI->fdes,data,8) != 8 ) return 0; /* if we got a list tag, ignore it */ - if(strncasecmp((char*)data,"LIST",4) == 0) + if(strncasecmp(data,"LIST",4) == 0) { lseek(AVI->fdes,4,SEEK_CUR); continue; } - n = PAD_EVEN(str2ulong(data+4)); + n = PAD_EVEN(str2ulong((unsigned char *)data+4)); - if(strncasecmp((char*)data,(char*)AVI->video_tag,3) == 0) + if(strncasecmp(data,AVI->video_tag,3) == 0) { *len = n; AVI->video_pos++; @@ -1219,10 +3448,10 @@ int AVI_read_data(avi_t *AVI, uint8_t *vidbuf, long max_vidbuf, lseek(AVI->fdes,n,SEEK_CUR); return -1; } - if(read(AVI->fdes,vidbuf,n) != n ) return 0; + if(avi_read(AVI->fdes,vidbuf,n) != n ) return 0; return 1; } - else if(strncasecmp((char*)data,(char*)AVI->audio_tag,4) == 0) + else if(strncasecmp(data,AVI->track[AVI->aptr].audio_tag,4) == 0) { *len = n; if(n>max_audbuf) @@ -1230,7 +3459,7 @@ int AVI_read_data(avi_t *AVI, uint8_t *vidbuf, long max_vidbuf, lseek(AVI->fdes,n,SEEK_CUR); return -2; } - if(read(AVI->fdes,audbuf,n) != n ) return 0; + if(avi_read(AVI->fdes,audbuf,n) != n ) return 0; return 2; break; } @@ -1241,7 +3470,7 @@ int AVI_read_data(avi_t *AVI, uint8_t *vidbuf, long max_vidbuf, /* AVI_print_error: Print most recent error (similar to perror) */ -const char *(avi_errors[]) = +char *(avi_errors[]) = { /* 0 */ "avilib - No Error", /* 1 */ "avilib - AVI file size limit reached", @@ -1257,20 +3486,20 @@ const char *(avi_errors[]) = /* 11 */ "avilib - AVI file has no MOVI list (corrupted?)", /* 12 */ "avilib - AVI file has no video data", /* 13 */ "avilib - operation needs an index", - /* 14 */ "avilib - Unkown Error", - /* 15 */ "avilib - AVI file is empty" + /* 14 */ "avilib - Unkown Error" }; static int num_avi_errors = sizeof(avi_errors)/sizeof(char*); static char error_string[4096]; -void AVI_print_error(const char *str) +void AVI_print_error(char *str) { int aerrno; aerrno = (AVI_errno>=0 && AVI_errnoriff.id ,buf+0, 4); + memcpy(&wave->riff.len ,buf+4, 4); + memcpy(&wave->riff.wave_id ,buf+8, 4); + + memcpy(&wave->format.id ,buf+12, 4); + memcpy(&wave->format.len ,buf+16, 4); + + memcpy(&wave->common.wFormatTag ,buf+20, 2); + memcpy(&wave->common.wChannels ,buf+22, 2); + memcpy(&wave->common.dwSamplesPerSec ,buf+24, 4); + memcpy(&wave->common.dwAvgBytesPerSec ,buf+28, 4); + memcpy(&wave->common.wBlockAlign ,buf+32, 2); + memcpy(&wave->common.wBitsPerSample ,buf+34, 2); + + memcpy(&wave->data.id ,buf+36, 4); + memcpy(&wave->data.len ,buf+40, 4); + + + /* + fprintf(stderr, "RIFF: %c%c%c%c| (%d) (%d)\n", + wave->riff.id[0], wave->riff.id[1], wave->riff.id[2], wave->riff.id[3], + sizeof (*wave), sizeof (struct wave_header)); + fprintf(stderr, "WAVE: %c%c%c%c|\n", + wave->riff.wave_id[0], wave->riff.wave_id[1], wave->riff.wave_id[2], wave->riff.wave_id[3]); + fprintf(stderr, "fmt : %c%c%c%c|\n", + wave->format.id[0], wave->format.id[1], wave->format.id[2], wave->format.id[3]); + fprintf(stderr, "data: %c%c%c%c|\n", + wave->data.id[0], wave->data.id[1], wave->data.id[2], wave->data.id[3]); + */ + + if( strncasecmp(wave->riff.id , "RIFF",4) != 0 || + strncasecmp(wave->riff.wave_id, "WAVE",4) != 0 || + strncasecmp(wave->format.id , "fmt ",4) != 0 ) + { + AVI_errno = AVI_ERR_NO_AVI; + return -1; + } + +#ifdef WORDS_BIGENDIAN +#define x_FIXUP(field) \ + ((field) = (sizeof(field) == 4 ? str2ulong((unsigned char*)&(field)) \ + : str2ushort((unsigned char*)&(field)))) + + x_FIXUP(wave->riff.len); + x_FIXUP(wave->format.len); + x_FIXUP(wave->common.wFormatTag); + x_FIXUP(wave->common.wChannels); + x_FIXUP(wave->common.dwSamplesPerSec); + x_FIXUP(wave->common.dwAvgBytesPerSec); + x_FIXUP(wave->common.wBlockAlign); + x_FIXUP(wave->common.wBitsPerSample); + x_FIXUP(wave->data.len); + +#undef x_FIXUP +#endif + + return 0; +} + +int AVI_write_wave_header( int fd, const struct wave_header * wave ) +{ + char buf[44]; + struct wave_header buffer = *wave; + + + +#ifdef WORDS_BIGENDIAN +#define x_FIXUP(field) \ + ((sizeof(field) == 4 ? long2str((unsigned char*)&(field),(field)) \ + : short2str((unsigned char*)&(field),(field)))) + + x_FIXUP(buffer.riff.len); + x_FIXUP(buffer.format.len); + x_FIXUP(buffer.common.wFormatTag); + x_FIXUP(buffer.common.wChannels); + x_FIXUP(buffer.common.dwSamplesPerSec); + x_FIXUP(buffer.common.dwAvgBytesPerSec); + x_FIXUP(buffer.common.wBlockAlign); + x_FIXUP(buffer.common.wBitsPerSample); + x_FIXUP(buffer.data.len); + +#undef x_FIXUP +#endif + + memcpy(buf+ 0, &buffer.riff.id, 4); + memcpy(buf+ 4, &buffer.riff.len, 4); + memcpy(buf+ 8, &buffer.riff.wave_id, 4); + + memcpy(buf+12, &buffer.format.id, 4); + memcpy(buf+16, &buffer.format.len, 4); + + memcpy(buf+20, &buffer.common.wFormatTag, 2); + memcpy(buf+22, &buffer.common.wChannels, 2); + memcpy(buf+24, &buffer.common.dwSamplesPerSec, 4); + memcpy(buf+28, &buffer.common.dwAvgBytesPerSec, 4); + memcpy(buf+32, &buffer.common.wBlockAlign, 2); + memcpy(buf+34, &buffer.common.wBitsPerSample, 2); + + memcpy(buf+36, &buffer.data.id, 4); + memcpy(buf+40, &buffer.data.len, 4); + + + // write raw data + if( avi_write (fd, buf, sizeof(buf)) != sizeof(buf) ) + { + AVI_errno = AVI_ERR_WRITE; + return -1; + } + + return 0; +} + +size_t AVI_read_wave_pcm_data( int fd, void * buffer, size_t buflen ) +{ + int doneread = avi_read(fd, buffer, buflen); + +#ifdef WORDS_BIGENDIAN + { + char * bufptr = buffer; + size_t i; + char tmp; + + for( i=0; i0 ) + { + buflen = datalen; + if( buflen > sizeof(buffer) ) + { + buflen = sizeof(buffer); + } + + for( i=0; ifdes; +} + +int AVI_video_compressor_type(avi_t *AVI) +{ + return AVI->ffmpeg_codec_id; +} diff --git a/veejay-ng/libel/avilib.h b/veejay-ng/libel/avilib.h index ca2ee901..6cac81b6 100644 --- a/veejay-ng/libel/avilib.h +++ b/veejay-ng/libel/avilib.h @@ -1,78 +1,256 @@ /* - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + * avilib.h + * + * Copyright (C) Thomas Östreich - June 2001 + * multiple audio track support Copyright (C) 2002 Thomas Östreich + * + * Original code: + * Copyright (C) 1999 Rainer Johanni + * + * This file is part of transcode, a video stream processing tool + * + * transcode is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * transcode 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ - This program 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 General Public License for more details. +#include +#include +#include +#include +#include +#include - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ +#include +#include +#include +#include + +#include #ifndef AVILIB_H #define AVILIB_H -#include -#include +#define AVI_MAX_TRACKS 8 typedef struct { - long pos; - long len; + off_t key; + off_t pos; + off_t len; } video_index_entry; typedef struct { - long pos; - long len; - long tot; + off_t pos; + off_t len; + off_t tot; } audio_index_entry; + +// Index types + + +#define AVI_INDEX_OF_INDEXES 0x00 // when each entry in aIndex + // array points to an index chunk +#define AVI_INDEX_OF_CHUNKS 0x01 // when each entry in aIndex + // array points to a chunk in the file +#define AVI_INDEX_IS_DATA 0x80 // when each entry is aIndex is + // really the data +// bIndexSubtype codes for INDEX_OF_CHUNKS +// +#define AVI_INDEX_2FIELD 0x01 // when fields within frames + // are also indexed + + + +typedef struct _avisuperindex_entry { + uint64_t qwOffset; // absolute file offset + uint32_t dwSize; // size of index chunk at this offset + uint32_t dwDuration; // time span in stream ticks +} avisuperindex_entry; + +typedef struct _avistdindex_entry { + uint32_t dwOffset; // qwBaseOffset + this is absolute file offset + uint32_t dwSize; // bit 31 is set if this is NOT a keyframe +} avistdindex_entry; + +// Standard index +typedef struct _avistdindex_chunk { + char fcc[4]; // ix## + uint32_t dwSize; // size of this chunk + uint16_t wLongsPerEntry; // must be sizeof(aIndex[0])/sizeof(DWORD) + uint8_t bIndexSubType; // must be 0 + uint8_t bIndexType; // must be AVI_INDEX_OF_CHUNKS + uint32_t nEntriesInUse; // + char dwChunkId[4]; // '##dc' or '##db' or '##wb' etc.. + uint64_t qwBaseOffset; // all dwOffsets in aIndex array are relative to this + uint32_t dwReserved3; // must be 0 + avistdindex_entry *aIndex; +} avistdindex_chunk; + + +// Base Index Form 'indx' +typedef struct _avisuperindex_chunk { + char fcc[4]; + uint32_t dwSize; // size of this chunk + uint16_t wLongsPerEntry; // size of each entry in aIndex array (must be 8 for us) + uint8_t bIndexSubType; // future use. must be 0 + uint8_t bIndexType; // one of AVI_INDEX_* codes + uint32_t nEntriesInUse; // index of first unused member in aIndex array + char dwChunkId[4]; // fcc of what is indexed + uint32_t dwReserved[3]; // meaning differs for each index type/subtype. + // 0 if unused + avisuperindex_entry *aIndex; // where are the ix## chunks + avistdindex_chunk **stdindex; // the ix## chunks itself (array) +} avisuperindex_chunk; + + + +typedef struct track_s +{ + + long a_fmt; /* Audio format, see #defines below */ + long a_chans; /* Audio channels, 0 for no audio */ + long a_rate; /* Rate in Hz */ + long a_bits; /* bits per audio sample */ + long mp3rate; /* mp3 bitrate kbs*/ + long a_vbr; /* 0 == no Variable BitRate */ + long padrate; /* byte rate used for zero padding */ + + long audio_strn; /* Audio stream number */ + off_t audio_bytes; /* Total number of bytes of audio data */ + long audio_chunks; /* Chunks of audio data in the file */ + + char audio_tag[4]; /* Tag of audio data */ + long audio_posc; /* Audio position: chunk */ + long audio_posb; /* Audio position: byte within chunk */ + + off_t a_codech_off; /* absolut offset of audio codec information */ + off_t a_codecf_off; /* absolut offset of audio codec information */ + + audio_index_entry *audio_index; + avisuperindex_chunk *audio_superindex; + +} track_t; + typedef struct { - long fdes; /* File descriptor of AVI file */ - long mode; /* 0 for reading, 1 for writing */ + uint32_t bi_size; + uint32_t bi_width; + uint32_t bi_height; + uint16_t bi_planes; + uint16_t bi_bit_count; + uint32_t bi_compression; + uint32_t bi_size_image; + uint32_t bi_x_pels_per_meter; + uint32_t bi_y_pels_per_meter; + uint32_t bi_clr_used; + uint32_t bi_clr_important; +} alBITMAPINFOHEADER; - long width; /* Width of a video frame */ - long height; /* Height of a video frame */ - double fps; /* Frames per second */ - char compressor[8]; /* Type of compressor, 4 bytes + padding for 0 byte */ - int ffmpeg_codec_id; /* Codec ID to avoid strcmp for compressor */ - long video_strn; /* Video stream number */ - long video_frames; /* Number of video frames */ - uint8_t video_tag[4]; /* Tag of video data */ - long video_pos; /* Number of next frame to be read - (if index present) */ +typedef struct __attribute__((__packed__)) +{ + uint16_t w_format_tag; + uint16_t n_channels; + uint32_t n_samples_per_sec; + uint32_t n_avg_bytes_per_sec; + uint16_t n_block_align; + uint16_t w_bits_per_sample; + uint16_t cb_size; +} alWAVEFORMATEX; - long a_fmt; /* Audio format, see #defines below */ - long a_chans; /* Audio channels, 0 for no audio */ - long a_rate; /* Rate in Hz */ - long a_bits; /* bits per audio clip */ - long audio_strn; /* Audio stream number */ - long audio_bytes; /* Total number of bytes of audio data */ - long audio_chunks; /* Chunks of audio data in the file */ - uint8_t audio_tag[4]; /* Tag of audio data */ - long audio_posc; /* Audio position: chunk */ - long audio_posb; /* Audio position: byte within chunk */ +typedef struct __attribute__((__packed__)) +{ + uint32_t fcc_type; + uint32_t fcc_handler; + uint32_t dw_flags; + uint32_t dw_caps; + uint16_t w_priority; + uint16_t w_language; + uint32_t dw_scale; + uint32_t dw_rate; + uint32_t dw_start; + uint32_t dw_length; + uint32_t dw_initial_frames; + uint32_t dw_suggested_buffer_size; + uint32_t dw_quality; + uint32_t dw_sample_size; + uint32_t dw_left; + uint32_t dw_top; + uint32_t dw_right; + uint32_t dw_bottom; + uint32_t dw_edit_count; + uint32_t dw_format_change_count; + char sz_name[64]; +} alAVISTREAMINFO; - long pos; /* position in file */ - long n_idx; /* number of index entries actually filled */ - long max_idx; /* number of index entries actually allocated */ - uint8_t (*idx)[16]; /* index entries (AVI idx1 tag) */ - video_index_entry * video_index; - audio_index_entry * audio_index; - long last_pos; /* Position of last frame written */ - long last_len; /* Length of last frame written */ - int must_use_index; /* Flag if frames are duplicated */ - long movi_start; - mmap_region_t *mmap_region; - off_t mmap_offset; - size_t mmap_size; +typedef struct +{ + + long fdes; /* File descriptor of AVI file */ + long mode; /* 0 for reading, 1 for writing */ + + long width; /* Width of a video frame */ + long height; /* Height of a video frame */ + double fps; /* Frames per second */ + char compressor[8]; /* Type of compressor, 4 bytes + padding for 0 byte */ + char compressor2[8]; /* Type of compressor, 4 bytes + padding for 0 byte */ + long video_strn; /* Video stream number */ + long video_frames; /* Number of video frames */ + char video_tag[4]; /* Tag of video data */ + long video_pos; /* Number of next frame to be read + (if index present) */ + + uint32_t max_len; /* maximum video chunk present */ + + track_t track[AVI_MAX_TRACKS]; // up to AVI_MAX_TRACKS audio tracks supported + + off_t pos; /* position in file */ + long n_idx; /* number of index entries actually filled */ + long max_idx; /* number of index entries actually allocated */ + + off_t v_codech_off; /* absolut offset of video codec (strh) info */ + off_t v_codecf_off; /* absolut offset of video codec (strf) info */ + + uint8_t (*idx)[16]; /* index entries (AVI idx1 tag) */ + + video_index_entry *video_index; + avisuperindex_chunk *video_superindex; /* index of indices */ + int is_opendml; /* set to 1 if this is an odml file with multiple index chunks */ + + off_t last_pos; /* Position of last frame written */ + uint32_t last_len; /* Length of last frame written */ + int must_use_index; /* Flag if frames are duplicated */ + off_t movi_start; + int total_frames; /* total number of frames if dmlh is present */ + + int anum; // total number of audio tracks + int aptr; // current audio working track + int comment_fd; // Read avi header comments from this fd + char *index_file; // read the avi index from this file + + alBITMAPINFOHEADER *bitmap_info_header; + alWAVEFORMATEX *wave_format_ex[AVI_MAX_TRACKS]; + + void* extradata; + unsigned long extradata_size; + + mmap_region_t *mmap_region; + off_t mmap_offset; + size_t mmap_size; + int ffmpeg_codec_id; } avi_t; #define AVI_MODE_WRITE 0 @@ -121,10 +299,11 @@ typedef struct getIndex==0, but an operation has been performed that needs an index */ -#define AVI_ERR_EMPTY 15 /* AVI file is empty (only header) */ +#define AVI_ERR_EMPTY 14 /* AVI file is empty (header only)*/ /* Possible Audio formats */ +#ifndef WAVE_FORMAT_PCM #define WAVE_FORMAT_UNKNOWN (0x0000) #define WAVE_FORMAT_PCM (0x0001) #define WAVE_FORMAT_ADPCM (0x0002) @@ -141,46 +320,144 @@ typedef struct #define IBM_FORMAT_MULAW (0x0101) #define IBM_FORMAT_ALAW (0x0102) #define IBM_FORMAT_ADPCM (0x0103) - +#endif avi_t* AVI_open_output_file(char * filename); -void AVI_set_video(avi_t *AVI, int width, int height, double fps, const char *compressor); +void AVI_set_video(avi_t *AVI, int width, int height, double fps, char *compressor); void AVI_set_audio(avi_t *AVI, int channels, long rate, int bits, int format); -int AVI_write_frame(avi_t *AVI, uint8_t *data, long bytes); +int AVI_write_frame(avi_t *AVI, char *data, long bytes); int AVI_dup_frame(avi_t *AVI); -int AVI_write_audio(avi_t *AVI, uint8_t *data, long bytes); +int AVI_write_audio(avi_t *AVI, char *data, long bytes); +int AVI_append_audio(avi_t *AVI, char *data, long bytes); long AVI_bytes_remain(avi_t *AVI); int AVI_close(avi_t *AVI); -int AVI_fileno(avi_t *AVI); +long AVI_bytes_written(avi_t *AVI); avi_t *AVI_open_input_file(char *filename, int getIndex, int mmap_size); - +avi_t *AVI_open_input_indexfile(char *filename, int getIndex, char *indexfile); +avi_t *AVI_open_fd(int fd, int getIndex, int mmap_size); +avi_t *AVI_open_indexfd(int fd, int getIndex, char *indexfile); +int avi_parse_input_file(avi_t *AVI, int getIndex); +int avi_parse_index_from_file(avi_t *AVI, char *filename); +long AVI_audio_mp3rate(avi_t *AVI); +long AVI_audio_padrate(avi_t *AVI); long AVI_video_frames(avi_t *AVI); int AVI_video_width(avi_t *AVI); int AVI_video_height(avi_t *AVI); double AVI_frame_rate(avi_t *AVI); char* AVI_video_compressor(avi_t *AVI); -int AVI_video_compressor_type(avi_t *AVI); int AVI_audio_channels(avi_t *AVI); int AVI_audio_bits(avi_t *AVI); int AVI_audio_format(avi_t *AVI); long AVI_audio_rate(avi_t *AVI); long AVI_audio_bytes(avi_t *AVI); +long AVI_audio_chunks(avi_t *AVI); +int AVI_can_read_audio(avi_t *AVI); + +long AVI_max_video_chunk(avi_t *AVI); long AVI_frame_size(avi_t *AVI, long frame); +long AVI_audio_size(avi_t *AVI, long frame); int AVI_seek_start(avi_t *AVI); int AVI_set_video_position(avi_t *AVI, long frame); -long AVI_read_frame(avi_t *AVI, uint8_t *vidbuf); -int AVI_set_audio_position(avi_t *AVI, long byte); -long AVI_read_audio(avi_t *AVI, uint8_t *audbuf, long bytes); +long AVI_get_video_position(avi_t *AVI, long frame); +long AVI_read_frame(avi_t *AVI, char *vidbuf, int *keyframe); -int AVI_read_data(avi_t *AVI, uint8_t *vidbuf, long max_vidbuf, - uint8_t *audbuf, long max_audbuf, +int AVI_set_audio_position(avi_t *AVI, long byte); +int AVI_set_audio_bitrate(avi_t *AVI, long bitrate); + +long AVI_get_audio_position_index(avi_t *AVI); +int AVI_set_audio_position_index(avi_t *AVI, long indexpos); + +long AVI_read_audio(avi_t *AVI, char *audbuf, long bytes); +long AVI_read_audio_chunk(avi_t *AVI, char *audbuf); + +long AVI_audio_codech_offset(avi_t *AVI); +long AVI_audio_codecf_offset(avi_t *AVI); +long AVI_video_codech_offset(avi_t *AVI); +long AVI_video_codecf_offset(avi_t *AVI); + +int AVI_read_data(avi_t *AVI, char *vidbuf, long max_vidbuf, + char *audbuf, long max_audbuf, long *len); -void AVI_print_error(const char *str); -const char *AVI_strerror(void); -const char *AVI_syserror(void); +void AVI_print_error(char *str); +char *AVI_strerror(void); +char *AVI_syserror(void); + +int AVI_scan(char *name); +int AVI_dump(char *name, int mode); + +char *AVI_codec2str(short cc); +int AVI_file_check(char *import_file); + +void AVI_info(avi_t *avifile); +uint64_t AVI_max_size(void); +int avi_update_header(avi_t *AVI); + +int AVI_set_audio_track(avi_t *AVI, int track); +int AVI_get_audio_track(avi_t *AVI); +int AVI_audio_tracks(avi_t *AVI); + +void AVI_set_audio_vbr(avi_t *AVI, long is_vbr); +long AVI_get_audio_vbr(avi_t *AVI); + +void AVI_set_comment_fd(avi_t *AVI, int fd); +int AVI_get_comment_fd(avi_t *AVI); + +struct riff_struct +{ + uint8_t id[4]; /* RIFF */ + uint32_t len; + uint8_t wave_id[4]; /* WAVE */ +}; + + +struct chunk_struct +{ + uint8_t id[4]; + uint32_t len; +}; + +struct common_struct +{ + uint16_t wFormatTag; + uint16_t wChannels; + uint32_t dwSamplesPerSec; + uint32_t dwAvgBytesPerSec; + uint16_t wBlockAlign; + uint16_t wBitsPerSample; /* Only for PCM */ +}; + +struct wave_header +{ + struct riff_struct riff; + struct chunk_struct format; + struct common_struct common; + struct chunk_struct data; +}; + +// Simple WAV IO +int AVI_read_wave_header( int fd, struct wave_header * wave ); +int AVI_write_wave_header( int fd, const struct wave_header * wave ); +size_t AVI_read_wave_pcm_data( int fd, void * buffer, size_t buflen ); +size_t AVI_write_wave_pcm_data( int fd, const void * buffer, size_t buflen ); + + +struct AVIStreamHeader { + long fccType; + long fccHandler; + long dwFlags; + long dwPriority; + long dwInitialFrames; + long dwScale; + long dwRate; + long dwStart; + long dwLength; + long dwSuggestedBufferSize; + long dwQuality; + long dwSampleSize; +}; #endif diff --git a/veejay-ng/libel/lav_io.c b/veejay-ng/libel/lav_io.c index 8906defe..440368b4 100644 --- a/veejay-ng/libel/lav_io.c +++ b/veejay-ng/libel/lav_io.c @@ -22,8 +22,6 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -/** \defgroup lavfile Linux Audio Video - support for AVI and others */ - #include #include #include @@ -34,6 +32,17 @@ #include //#include #include +#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; @@ -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; @@ -68,7 +79,10 @@ void lav_set_project(int w, int h, float f, int fmt) output_fps = f; output_yuv = fmt; } - +#else +void lav_set_project(int w, int h, float f, int fmt) +{ +} #endif #define M_SOF0 0xC0 @@ -82,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); @@ -258,7 +286,6 @@ int lav_query_polarity(char format) case 'D': return LAV_NOT_INTERLACED; //divx case 'Y': return LAV_NOT_INTERLACED; // planar yuv 4:2:0 (yv12) case 'P': return LAV_NOT_INTERLACED; // planar yuv 4:2:2 (yv16) - case 'Q': return LAV_NOT_INTERLACED; case 'M': return LAV_NOT_INTERLACED; // mpeg4 , case 'd': return LAV_INTER_BOTTOM_FIRST; // DV, interlaced case 'j': return LAV_INTER_TOP_FIRST; @@ -281,46 +308,10 @@ lav_file_t *lav_open_output_file(char *filename, char format, int width, int height, int interlaced, double fps, int asize, int achans, long arate) { - char fourcc[5]; - int is_avi = 1; - - switch(format) - { - case 'a': // mjpeg - sprintf(fourcc,"%s", "mjpg" ); break; - case 'd': // digital video - sprintf(fourcc,"%s", "dvsd" ); break; - case 'D': // divx - sprintf(fourcc, "%s", "div3"); break; - case 'L': //lossless - sprintf(fourcc, "%s", "ljpg"); break; - case 'A': //mjpegB - sprintf(fourcc, "%s", "mjpa"); break; - case 'H': //huffyuv - sprintf(fourcc, "%s", "hfyu"); break; - case 'M': //mpeg4 - sprintf(fourcc, "%s", "MP4V" ); break; - case 'P': //yuv422 planar - sprintf(fourcc, "%s", "YV16") ; break; - case 'Y': //yuv420 planar - sprintf(fourcc, "%s", "IYUV") ; break; - case 'Q': //yuv444 planar - sprintf(fourcc, "%s", "i444") ; break; - case 'b': - sprintf(fourcc, "%s", "dvsd") ; - // is_avi = 0; - break; - default: - veejay_msg(0, - "Invalid format"); - return NULL; - break; - - } - lav_file_t *lav_fd = (lav_file_t*) malloc(sizeof(lav_file_t)); - if(lav_fd==0) { internal_error=ERROR_MALLOC; return 0; } + if(lav_fd==0) { internal_error=ERROR_MALLOC; return NULL; } + /* Set lav_fd */ lav_fd->avi_fd = 0; @@ -332,31 +323,157 @@ lav_file_t *lav_open_output_file(char *filename, char format, lav_fd->is_MJPG = 1; lav_fd->MJPG_chroma = _lav_io_default_chroma; - if( is_avi ) - lav_fd->avi_fd = AVI_open_output_file(filename); + switch(format) + { + case 'a': + case 'A': + /* Open AVI output file */ + veejay_msg(VEEJAY_MSG_DEBUG, "\tWriting output file in AVI MJPEG"); + lav_fd->avi_fd = AVI_open_output_file(filename); + if(!lav_fd->avi_fd) + { + free(lav_fd); + return NULL; + } + AVI_set_video(lav_fd->avi_fd, width, height, fps, "MJPG"); + if (asize) + AVI_set_audio(lav_fd->avi_fd, achans, arate, asize, WAVE_FORMAT_PCM); + return lav_fd; + case 'Y': + veejay_msg(VEEJAY_MSG_DEBUG,"\tWriting output file in AVI IYUV"); + lav_fd->avi_fd = AVI_open_output_file(filename); + if(!lav_fd->avi_fd) + { + free(lav_fd); + return NULL; + } + AVI_set_video(lav_fd->avi_fd, width,height,fps, "iyuv"); + if(asize) + AVI_set_audio(lav_fd->avi_fd, achans,arate,asize,WAVE_FORMAT_PCM); + return lav_fd; + case 'P': + veejay_msg(VEEJAY_MSG_DEBUG, "\tWriting output file in AVI yv16"); + lav_fd->avi_fd = AVI_open_output_file(filename); + if(!lav_fd->avi_fd) + { + free(lav_fd); + return NULL; + } + AVI_set_video(lav_fd->avi_fd, width,height,fps, "yv16"); + if(asize) + AVI_set_audio(lav_fd->avi_fd, achans,arate,asize,WAVE_FORMAT_PCM); + return lav_fd; + case 'D': + veejay_msg(VEEJAY_MSG_DEBUG, "\tWriting output file in AVI div3"); + lav_fd->avi_fd = AVI_open_output_file(filename); + if(!lav_fd->avi_fd) + { + free(lav_fd); + return NULL; + } + AVI_set_video(lav_fd->avi_fd,width,height,fps, "div3"); + if(asize) + AVI_set_audio(lav_fd->avi_fd,achans,arate,asize,WAVE_FORMAT_PCM); + return lav_fd; + case 'M': + veejay_msg(VEEJAY_MSG_DEBUG, "\tWriting output file in AVI mp4v"); + lav_fd->avi_fd = AVI_open_output_file(filename); + if(!lav_fd->avi_fd) + { + free(lav_fd); + return NULL; + } + AVI_set_video(lav_fd->avi_fd,width,height,fps, "mp4v"); + if(asize) + AVI_set_audio(lav_fd->avi_fd,achans,arate,asize,WAVE_FORMAT_PCM); + return lav_fd; + case 'b': + case 'd': + veejay_msg(VEEJAY_MSG_DEBUG, "\tWriting output file in AVI dvsd"); + lav_fd->avi_fd = AVI_open_output_file(filename); + if(!lav_fd->avi_fd) + { + free(lav_fd); + return NULL; + } + 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': + case 'Q': +#ifdef HAVE_LIBQUICKTIME + /* open quicktime output file */ - if(!lav_fd->avi_fd) { free(lav_fd); return 0; } - - AVI_set_video(lav_fd->avi_fd, width, height, fps, fourcc); + /* since the documentation says that the file should be empty, + we try to remove it first */ + veejay_msg(VEEJAY_MSG_DEBUG, "\tWriting output file in Quicktime MJPA/JPEG"); + remove(filename); - if (asize) AVI_set_audio(lav_fd->avi_fd, achans, arate, asize, WAVE_FORMAT_PCM); + lav_fd->qt_fd = quicktime_open(filename, 0, 1); + if(!lav_fd->qt_fd) + { + veejay_msg(VEEJAY_MSG_ERROR, "\tCannot open '%s' for writing", filename); + free(lav_fd); + return NULL; + } + if(format=='q') + quicktime_set_video(lav_fd->qt_fd, 1, width, height, fps, + (interlaced ? QUICKTIME_MJPA : QUICKTIME_JPEG)); + else + quicktime_set_video(lav_fd->qt_fd,1, width,height,fps, + QUICKTIME_DV ); + if (asize) + quicktime_set_audio(lav_fd->qt_fd, achans, arate, asize, QUICKTIME_TWOS); - return lav_fd; + int has_kf = quicktime_has_keyframes( lav_fd->qt_fd, 0 ); + char *copyright = quicktime_get_copyright( lav_fd->qt_fd ); + char *name = quicktime_get_name( lav_fd->qt_fd ); + char *info = quicktime_get_info( lav_fd->qt_fd ); + + veejay_msg(VEEJAY_MSG_DEBUG, + "(C) %s by %s, %s, has keyframes = %d", copyright,name,info,has_kf ); + + + return lav_fd; +#else + veejay_msg(0,"Quicktime not included in build process. Abort"); + internal_error = ERROR_FORMAT; + return NULL; +#endif + + } + if(lav_fd) free(lav_fd); + return NULL; } int lav_close(lav_file_t *lav_file) { int ret = 0; - video_format = lav_file->format; internal_error = 0; /* for error messages */ - + video_format = lav_file->format; internal_error = 0; /* for error messages */ switch(video_format) { #ifdef SUPPORT_READ_DV2 + case 'd': case 'b': + veejay_msg(VEEJAY_MSG_DEBUG,"\tClosing raw dv file"); ret = rawdv_close(lav_file->dv_fd); break; #endif +#ifdef USE_GDK_PIXBUF + case 'x': + veejay_msg(VEEJAY_MSG_DEBUG,"\tClosing image file"); + vj_picture_cleanup( lav_file->picture ); + ret = 1; + break; +#endif +#ifdef HAVE_LIBQUICKTIME + case 'q': + veejay_msg(VEEJAY_MSG_DEBUG, "\tClosing Quicktime file"); + ret = quicktime_close( lav_file->qt_fd ); + break; +#endif default: + veejay_msg(VEEJAY_MSG_DEBUG, "\tClosing AVI file"); ret = AVI_close(lav_file->avi_fd); break; } @@ -373,11 +490,58 @@ int lav_write_frame(lav_file_t *lav_file, uint8_t *buff, long size, long count) long jpglen = 0; video_format = lav_file->format; internal_error = 0; /* for error messages */ +#ifdef SUPPORT_READ_DV2 + if(video_format == 'b') + return -1; +#endif /* For interlaced video insert the apropriate APPn markers */ - - if(lav_file->interlacing!=LAV_NOT_INTERLACED && (lav_file->format == 'a' || lav_file->format=='A' || - lav_file->format == 'L')) +#ifdef USE_GDK_PIXBUF + if(video_format == 'x') + return -1; +#endif + 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; @@ -385,49 +549,108 @@ 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': + case 'M': + case 'P': + case 'D': + case 'Y': 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 */ -#ifdef SUPPORT_READ_DV2 - if(video_format == 'b') - return 0; + 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 - return AVI_write_audio( lav_file->avi_fd, buff, samps*lav_file->bps); + 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 + case 'b': + return 0; +#endif +#ifdef USE_GDK_PIXBUF + case 'x': + return 0; +#endif + case 'a': + case 'A': + return AVI_write_audio( lav_file->avi_fd, buff, samps*lav_file->bps); + } + return 0; } @@ -435,51 +658,124 @@ 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 'P': + case 'Y': + case 'D': + case 'M': + 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 - return AVI_video_frames(lav_file->avi_fd); +#ifdef USE_GDK_PIXBUF + case 'x': + return 2; +#endif +#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': + case 'P': + case 'M': + case 'D': + case 'Y': + 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 - return AVI_video_width(lav_file->avi_fd); +#ifdef USE_GDK_PIXBUF + case 'x': + return (output_scale_width == 0 ? vj_picture_get_width( lav_file->picture ) : output_scale_width); +#endif +#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': + case 'P': + case 'M': + case 'D': + case 'Y': + 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 - return AVI_video_height(lav_file->avi_fd); +#ifdef USE_GDK_PIXBUF + case 'x': + return (output_scale_height == 0 ? vj_picture_get_height( lav_file->picture ) : output_scale_height); +#endif +#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 - return AVI_frame_rate(lav_file->avi_fd); +#ifdef USE_GDK_PIXBUF + case 'x': + return output_fps; +#endif +#ifdef HAVE_LIBQUICKTIME + case 'q': + return quicktime_frame_rate(lav_file->qt_fd,0); +#endif + default: + return AVI_frame_rate( lav_file->avi_fd); + } + return -1; } int lav_video_interlacing(lav_file_t *lav_file) { - video_format = lav_file->format; internal_error = 0; /* for error messages */ #ifdef SUPPORT_READ_DV2 if(video_format == 'b') return rawdv_interlacing(lav_file->dv_fd); #endif - return lav_file->interlacing; +#ifdef USE_GDK_PIXBUF + if(video_format == 'x') + return LAV_NOT_INTERLACED; +#endif + return lav_file->interlacing; } void lav_video_clipaspect(lav_file_t *lav_file, int *sar_w, int *sar_h) @@ -498,11 +794,68 @@ 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) +{ + 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 if(lav_file->format == 'b') return rawdv_compressor( lav_file->dv_fd ); +#endif +#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); + return vj_el_get_decoder_from_fourcc( compressor ); + } + // return quicktime_video_compressor(lav_file->qt_fd,0); #endif return AVI_video_compressor_type( lav_file->avi_fd ); } @@ -516,6 +869,17 @@ const char *lav_video_compressor(lav_file_t *lav_file) const char *tmp = (const char*) strdup("dvsd"); return tmp; } +#endif +#ifdef USE_GDK_PIXBUF + if( video_format == 'x') + { + 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); } @@ -527,6 +891,14 @@ int lav_audio_channels(lav_file_t *lav_file) #ifdef SUPPORT_READ_DV2 if(video_format == 'b') return rawdv_audio_channels(lav_file->dv_fd); +#endif +#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); } @@ -539,6 +911,14 @@ int lav_audio_bits(lav_file_t *lav_file) if(video_format == 'b') return rawdv_audio_bits(lav_file->dv_fd); #endif +#ifdef USE_GDK_PIXBUF + 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)); } @@ -550,6 +930,14 @@ long lav_audio_rate(lav_file_t *lav_file) if(video_format=='b') return rawdv_audio_rate(lav_file->dv_fd); #endif +#ifdef USE_GDK_PIXBUF + 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)); } @@ -561,6 +949,14 @@ long lav_audio_clips(lav_file_t *lav_file) if(video_format=='b') return rawdv_audio_bps(lav_file->dv_fd); #endif +#ifdef USE_GDK_PIXBUF + 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); } @@ -571,6 +967,14 @@ long lav_frame_size(lav_file_t *lav_file, long frame) if(video_format == 'b') return rawdv_frame_size( lav_file->dv_fd ); #endif +#ifdef USE_GDK_PIXBUF + 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)); } @@ -580,6 +984,13 @@ int lav_seek_start(lav_file_t *lav_file) #ifdef SUPPORT_READ_DV2 if(video_format == 'b') return rawdv_set_position( lav_file->dv_fd, 0 ); +#endif +#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)); } @@ -591,6 +1002,14 @@ int lav_set_video_position(lav_file_t *lav_file, long frame) if(video_format == 'b') return rawdv_set_position( lav_file->dv_fd, frame ); #endif +#ifdef USE_GDK_PIXBUF + 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)); } @@ -603,9 +1022,41 @@ int lav_read_frame(lav_file_t *lav_file, uint8_t *vidbuf) return rawdv_read_frame( lav_file->dv_fd, vidbuf ); } #endif - return (AVI_read_frame(lav_file->avi_fd,vidbuf)); +#ifdef USE_GDK_PIXBUF + 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 + int kf = 1; + int ret = (AVI_read_frame(lav_file->avi_fd,vidbuf,&kf)); + + if(!kf) + { + veejay_msg(0, "Requested frame is not a keyframe"); + return 0; + } + + return ret; + } +#ifdef USE_GDK_PIXBUF +uint8_t *lav_get_frame_ptr( lav_file_t *lav_file ) +{ + if(lav_file->format == 'x') + return vj_picture_get( lav_file->picture ); + return NULL; +} +#else +uint8_t *lav_get_frame_ptr( lav_file_t *lav_file) +{ + return NULL; +} +#endif + int lav_is_DV(lav_file_t *lav_file) { #ifdef SUPPORT_READ_DV2 @@ -622,12 +1073,21 @@ int lav_set_audio_position(lav_file_t *lav_file, long clip) #ifdef SUPPORT_READ_DV2 if(video_format == 'b') return 0; +#endif +#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; @@ -636,8 +1096,59 @@ long lav_read_audio(lav_file_t *lav_file, uint8_t *audbuf, long samps) #ifdef SUPPORT_READ_DV2 if(video_format == 'b') return rawdv_read_audio_frame( lav_file->dv_fd, audbuf ); +#endif +#ifdef USE_GDK_PIXBUF + if(video_format == 'x') + 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); } @@ -655,12 +1166,15 @@ lav_file_t *lav_open_input_file(char *filename, int mmap_size) int jpg_height, jpg_width, ncomps, hf[3], vf[3]; int ierr; - lav_file_t *lav_fd = (lav_file_t*) malloc(sizeof(lav_file_t)); + lav_file_t *lav_fd = (lav_file_t*) vj_malloc(sizeof(lav_file_t)); if(lav_fd==0) { internal_error=ERROR_MALLOC; return 0; } /* Set lav_fd */ +#ifdef HAVE_LIBQUICKTIME + char *audio_comp; +#endif lav_fd->avi_fd = 0; #ifdef SUPPORT_READ_DV2 lav_fd->dv_fd = 0; @@ -678,12 +1192,14 @@ lav_file_t *lav_open_input_file(char *filename, int mmap_size) lav_fd->MJPG_chroma = CHROMAUNKNOWN; lav_fd->mmap_size = mmap_size; + int ret = 0; /* open file, check if file is a file */ struct stat s; if( stat(filename, &s ) != 0 ) { if(lav_fd) free(lav_fd); + veejay_msg(VEEJAY_MSG_ERROR, "Invalid file '%s'. Proper permissions?",filename); return NULL; } @@ -695,142 +1211,326 @@ 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 */ + lav_fd->avi_fd = AVI_open_input_file(filename,1,mmap_size); - // if(!lav_fd->avi_fd) { if(lav_fd) free(lav_fd); return 0;} - if(lav_fd->avi_fd==NULL && AVI_errno == AVI_ERR_EMPTY ) - { - veejay_msg(0, "Not an AVI file or AVI file is empty"); + if( lav_fd->avi_fd && AVI_errno == AVI_ERR_EMPTY ) + { + veejay_msg(VEEJAY_MSG_ERROR, "Empty AVI file"); if(lav_fd) free(lav_fd); return NULL; - } - - if(lav_fd->avi_fd) - { - /* It is an AVI file */ - lav_fd->format = 'a'; - lav_fd->has_audio = (AVI_audio_bits(lav_fd->avi_fd)>0 && + } + else if ( lav_fd->avi_fd && AVI_errno == 0 ) + { + veejay_msg(VEEJAY_MSG_DEBUG, + "\tFile is AVI" ); + ret =1; + } + + int alt = 0; + + if(lav_fd->avi_fd) + { + ret = 1; + alt = 1; + lav_fd->format = 'a'; + lav_fd->has_audio = (AVI_audio_bits(lav_fd->avi_fd)>0 && AVI_audio_format(lav_fd->avi_fd)==WAVE_FORMAT_PCM); - video_comp = AVI_video_compressor(lav_fd->avi_fd); - veejay_msg(0, "Found AVI file with %s fourcc", video_comp ); - if(video_comp == NULL || strlen(video_comp) <= 0) - { if(lav_fd) free(lav_fd); return 0;} - } - else if( AVI_errno==AVI_ERR_NO_AVI ) - { - int ret = 0; -#ifdef SUPPORT_READ_DV2 - lav_fd->dv_fd = rawdv_open_input_file(filename,mmap_size); - if(lav_fd->dv_fd > 0) - { - lav_fd->MJPG_chroma = rawdv_sampling( lav_fd->dv_fd ); - if ( lav_fd->MJPG_chroma == -1 ) + video_comp = AVI_video_compressor(lav_fd->avi_fd); + if(video_comp == NULL || strlen(video_comp) <= 0) { - veejay_msg(VEEJAY_MSG_ERROR, "Dont know how to treat this file"); - ret = 0; + veejay_msg(VEEJAY_MSG_ERROR, "Unable to read FOURCC from AVI"); + if(lav_fd) free(lav_fd); + return 0; } - else + veejay_msg(VEEJAY_MSG_DEBUG, "\tFOURCC is %s", video_comp ); + } + else if( AVI_errno==AVI_ERR_NO_AVI || !lav_fd->avi_fd) + { +#ifdef HAVE_LIBQUICKTIME + if(quicktime_check_sig(filename)) { - video_comp = rawdv_video_compressor( lav_fd->dv_fd ); - lav_fd->format = 'b'; - lav_fd->has_audio = 0; + 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; + } + else + veejay_msg(VEEJAY_MSG_DEBUG, "\tOpening Quicktime file"); + lav_fd->avi_fd = NULL; + lav_fd->format = 'q'; + video_comp = quicktime_video_compressor(lav_fd->qt_fd,0); + veejay_msg(VEEJAY_MSG_DEBUG,"\tFile has fourcc '%s'", + video_comp ); + /* 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 + veejay_msg(VEEJAY_MSG_DEBUG, "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; + else + veejay_msg(VEEJAY_MSG_WARNING, "Audio compressor '%s' not supported", + audio_comp ); + } + alt = 1; ret = 1; } - } + else + veejay_msg(VEEJAY_MSG_DEBUG, "\tNot a Quicktime file"); #endif - if(ret == 0 || video_comp == NULL) +#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; + veejay_msg(VEEJAY_MSG_DEBUG, + "\tLoaded image file"); + } + else + veejay_msg(VEEJAY_MSG_DEBUG, + "\tNot a Image file"); + } +#endif + +#ifdef SUPPORT_READ_DV2 + if(!alt) + { + ret = 0; + lav_fd->dv_fd = rawdv_open_input_file(filename,mmap_size); + if(lav_fd->dv_fd > 0) + { + 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; + alt = 1; + veejay_msg(VEEJAY_MSG_DEBUG, + "RAW DV file '%s'", + video_comp ); + } + } + else + veejay_msg(VEEJAY_MSG_DEBUG, "\tNot a raw dv file"); + } +#endif + } + + if(ret == 0 || video_comp == NULL || alt == 0) { free(lav_fd); internal_error = ERROR_FORMAT; /* Format not recognized */ - veejay_msg(VEEJAY_MSG_ERROR, "Unable to load file '%s'", filename); + veejay_msg(VEEJAY_MSG_ERROR, "Unable to load file '%s', code=%x, video=%s", filename,ret,video_comp); return 0; } - } - + 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 */ - - if(strncasecmp(video_comp, "div3",4)==0) - { - lav_fd->MJPG_chroma = CHROMA420; - lav_fd->format = 'D'; - lav_fd->interlacing = LAV_NOT_INTERLACED; - veejay_msg(VEEJAY_MSG_WARNING, "Playing MS MPEG4v3 DivX Video. (Every frame should be an intra frame)" ); - return lav_fd; - } + + +#ifdef USE_GDK_PIXBUF + if(strncasecmp(video_comp, "PICT",4) == 0 ) + { + lav_fd->MJPG_chroma = (output_yuv == 1 ? CHROMA420: CHROMA422 ); + lav_fd->format = 'x'; + lav_fd->interlacing = LAV_NOT_INTERLACED; + return lav_fd; + } +#endif + - if(strncasecmp(video_comp,"mp4v",4)==0) - { - lav_fd->MJPG_chroma = CHROMA420; - lav_fd->format = 'M'; - lav_fd->interlacing = LAV_NOT_INTERLACED; - veejay_msg(VEEJAY_MSG_WARNING, "Playing MPEG4 Video (Every frame should be an intra frame)"); - return lav_fd; - } + if( strncasecmp(video_comp, "div3",4)==0 || + strncasecmp(video_comp, "mp43",4)==0 || + strncasecmp(video_comp, "mp42",4)==0 ) + { + lav_fd->MJPG_chroma = CHROMA420; + lav_fd->interlacing = LAV_NOT_INTERLACED; + veejay_msg(VEEJAY_MSG_WARNING, "Playing MS MPEG4v3 DivX Video. (Every frame should be an intra frame)" ); + return lav_fd; + } - /* Check compressor, no further action if not Motion JPEG/DV */ - if (strncasecmp(video_comp,"iyuv",4)==0) - { - lav_fd->MJPG_chroma = CHROMA420; - lav_fd->format = 'Y'; - lav_fd->interlacing = LAV_NOT_INTERLACED; - return lav_fd; - } - - if (strncasecmp(video_comp,"yv16",4)==0) - { - lav_fd->MJPG_chroma = CHROMA422; - lav_fd->format = 'P'; - lav_fd->interlacing = LAV_NOT_INTERLACED; - return lav_fd; - } - - if( strncasecmp( video_comp, "i444",4 ) == 0 ) - { - lav_fd->MJPG_chroma = CHROMA444; - lav_fd->format = 'Q'; - lav_fd->interlacing = LAV_NOT_INTERLACED; - return lav_fd; - - } - - if (strncasecmp(video_comp,"dvsd",4)==0 || strncasecmp(video_comp,"dv",2)==0) - { - int gw = lav_video_height( lav_fd ); - if( gw == 480 ) - lav_fd->MJPG_chroma = CHROMA411; - else + if( strncasecmp(video_comp,"mp4v",4 )==0 || + strncasecmp(video_comp,"divx",4 ) == 0 || + strncasecmp(video_comp,"xvid",4 ) == 0 || + strncasecmp(video_comp,"dxsd",4 ) == 0 || + strncasecmp(video_comp,"mp4s",4 ) == 0 || + strncasecmp(video_comp,"m4s2",4 ) == 0 ) + { + lav_fd->format = 'D'; + lav_fd->MJPG_chroma = CHROMA420; + lav_fd->interlacing = LAV_NOT_INTERLACED; + veejay_msg(VEEJAY_MSG_WARNING, "Playing MPEG4 Video (Every frame should be an intra frame)"); + return lav_fd; + } + + if ( strncasecmp(video_comp,"iyuv",4)==0 || + strncasecmp(video_comp,"i420",4)==0) + { + lav_fd->MJPG_chroma = CHROMA420; + lav_fd->format = 'Y'; + lav_fd->interlacing = LAV_NOT_INTERLACED; + return lav_fd; + } + + if ( strncasecmp(video_comp,"yv16",4)==0 || + strncasecmp(video_comp,"i422",4)==0 || + strncasecmp(video_comp,"hfyu",4)==0) + { lav_fd->MJPG_chroma = CHROMA422; + lav_fd->format = 'P'; + lav_fd->interlacing = LAV_NOT_INTERLACED; + return lav_fd; + } + + if( strncasecmp(video_comp, "avc1", 4 ) == 0 || + strncasecmp(video_comp, "h264", 4 ) == 0 || + strncasecmp(video_comp, "x264", 4 ) == 0 || + strncasecmp(video_comp, "davc", 4 ) == 0 ) + { + lav_fd->MJPG_chroma = CHROMA420; + lav_fd->interlacing = LAV_NOT_INTERLACED; + return lav_fd; + } + + if ( strncasecmp(video_comp,"dvsd",4)==0 || + strncasecmp(video_comp,"dvcp",4) ==0 || + strncasecmp(video_comp,"dxsd",4) == 0 || + strncasecmp(video_comp, "dvp",3) == 0 || + strncasecmp(video_comp, "dvhd",4) == 0 || + strncasecmp(video_comp, "dv",2 ) == 0) + { + int gw = lav_video_height( lav_fd ); + if( gw == 480 ) + lav_fd->MJPG_chroma = CHROMA411; + else + lav_fd->MJPG_chroma = CHROMA422; + lav_fd->interlacing = LAV_INTER_BOTTOM_FIRST; - return lav_fd; - } + return lav_fd; + } - if( strncasecmp( video_comp, "hfyu", 4 ) == 0 ) - { - lav_fd->MJPG_chroma = CHROMA422; - lav_fd->format = 'H'; - lav_fd->interlacing = LAV_NOT_INTERLACED; - return lav_fd; - } + if( strncasecmp(video_comp, "png", 3 ) == 0 || + strncasecmp(video_comp, "mpng",4) == 0 ) + { + lav_fd->MJPG_chroma = CHROMA420; + lav_fd->interlacing = LAV_INTER_UNKNOWN; + return lav_fd; + } - if (strncasecmp(video_comp, "mjpg", 4) == 0 || strncasecmp(video_comp,"mjpa",4)==0 || - strncasecmp(video_comp, "jpeg", 4) == 0 || strncasecmp( video_comp ,"ljpg",4 ) == 0 ) - { - lav_fd->MJPG_chroma = CHROMA420; - lav_fd->format = 'a'; - lav_fd->interlacing = LAV_INTER_UNKNOWN; - lav_fd->is_MJPG = 1; - ierr = 0; - frame = NULL; - if ( lav_set_video_position(lav_fd,0) ) goto ERREXIT; - if ( (len = lav_frame_size(lav_fd,0)) <=0 ) goto ERREXIT; - if ( (frame = (unsigned char*) malloc(len)) == 0 ) { ierr=ERROR_MALLOC; goto ERREXIT; } + if( strncasecmp(video_comp, "svq1", 4 ) == 0 || + strncasecmp(video_comp, "svq3", 4 ) == 0 || + strncasecmp(video_comp, "rpza", 4 ) == 0 || + strncasecmp(video_comp, "cyuv", 4 ) == 0 ) + { + lav_fd->MJPG_chroma = CHROMA420; + lav_fd->interlacing = LAV_INTER_UNKNOWN; + return lav_fd; + } + + if ( strncasecmp(video_comp,"mjpg", 4) == 0 || + strncasecmp(video_comp,"mjpa", 4) == 0 || + strncasecmp(video_comp,"jpeg", 4) == 0 || + strncasecmp(video_comp,"mjpb" ,4) == 0 || + strncasecmp(video_comp,"sp5x", 4) == 0 || + strncasecmp(video_comp,"jpgl", 4) == 0 || + strncasecmp(video_comp , "jfif", 4 ) == 0 || + strncasecmp(video_comp, "dmb1", 4)==0 ) + { + lav_fd->MJPG_chroma = CHROMA420; + lav_fd->interlacing = LAV_INTER_UNKNOWN; + lav_fd->is_MJPG = 1; + + /* Make some checks on the video source, we read the first frame for that */ - if ( lav_read_frame(lav_fd,frame) <= 0 ) goto ERREXIT; - if ( lav_set_video_position(lav_fd,0) ) goto ERREXIT; - if( scan_jpeg(frame, len, 1) ) { ierr=ERROR_JPEG; goto ERREXIT; } + ierr = 0; + frame = NULL; + if ( lav_set_video_position(lav_fd,0) ) goto ERREXIT; + if ( (len = lav_frame_size(lav_fd,0)) <=0 ) goto ERREXIT; + if ( (frame = (unsigned char*) malloc(len)) == 0 ) { ierr=ERROR_MALLOC; goto ERREXIT; } + + if ( lav_read_frame(lav_fd,frame) <= 0 ) goto ERREXIT; + /* reset video position to 0 */ + if ( lav_set_video_position(lav_fd,0) ) goto ERREXIT; + if( scan_jpeg(frame, len, 1) ) { ierr=ERROR_JPEG; goto ERREXIT; } + + /* We have to look to the JPEG SOF marker for further information + The SOF marker has the following format: + + FF + C0 + len_hi + len_lo + data_precision + height_hi + height_lo + width_hi + width_lo + num_components + + And then 3 bytes for each component: + + Component id + H, V sampling factors (as nibbles) + Quantization table number + */ /* Check if the JPEG has the special 4:2:2 format needed for some HW JPEG decompressors (the Iomega Buz, for example) */ @@ -919,15 +1619,16 @@ lav_file_t *lav_open_input_file(char *filename, int mmap_size) if(frame) free(frame); return lav_fd; - } - - ierr = ERROR_FORMAT; + } + ierr = ERROR_FORMAT; + veejay_msg(VEEJAY_MSG_ERROR, "Unrecognized format '%s'", video_comp); ERREXIT: lav_close(lav_fd); if(frame) free(frame); internal_error = ierr; + veejay_msg(VEEJAY_MSG_ERROR, "%s", lav_strerror()); return 0; } @@ -971,15 +1672,22 @@ const char *lav_strerror(void) internal_error = 0; return error_string; } - if( video_format == 'b' ) - { - sprintf(error_string, "rawdv strerror() not implemented"); - internal_error = 0; - return error_string; - } - - return AVI_strerror(); + switch(video_format) + { + case 'a': + case 'A': + case 'Y': + case 'M': + case 'P': + case 'D': + return AVI_strerror(); + default: + /* No or unknown video format */ + if(errno) strerror(errno); + else sprintf(error_string,"No or unknown video format"); + return error_string; + } } @@ -1051,17 +1759,65 @@ int lav_fileno(lav_file_t *lav_file) switch(lav_file->format) { - case 'b': - res = -1; - break; - default: + case 'a': + case 'A': + case 'P': + case 'D': + case 'Y': + case 'M': res = AVI_fileno( lav_file->avi_fd ); - break; + break; +#ifdef HAVE_LIBQUICKTIME + case 'q': +// res = lqt_fileno((quicktime_t *)lav_file->qt_fd); +// + { + quicktime_t *q = lav_file->qt_fd; + res = (int)fileno( (quicktime_t*) q->stream ); + } + break; +#endif + default: + res = -1; } 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; +} + @@ -1074,4 +1830,3 @@ int lav_fileno(lav_file_t *lav_file) - diff --git a/veejay-ng/libel/lav_io.h b/veejay-ng/libel/lav_io.h index 335b798d..3a03de59 100644 --- a/veejay-ng/libel/lav_io.h +++ b/veejay-ng/libel/lav_io.h @@ -30,7 +30,7 @@ // play with mlt here, avformat producer/several consumers (we can write to) // for normalized output (720x576/480) , dv1394 capture and playback -#include +#include #define LAV_INTER_UNKNOWN Y4M_UNKNOWN #define LAV_NOT_INTERLACED Y4M_ILACE_NONE @@ -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-ng/ui/Makefile.in b/veejay-ng/ui/Makefile.in deleted file mode 100644 index d7d3e4a6..00000000 --- a/veejay-ng/ui/Makefile.in +++ /dev/null @@ -1,630 +0,0 @@ -# Makefile.in generated by automake 1.9.5 from Makefile.am. -# @configure_input@ - -# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, -# 2003, 2004, 2005 Free Software Foundation, Inc. -# This Makefile.in is free software; the Free Software Foundation -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. - -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY, to the extent permitted by law; without -# even the implied warranty of MERCHANTABILITY or FITNESS FOR A -# PARTICULAR PURPOSE. - -@SET_MAKE@ - -# Makefile for veejay ui - - -SOURCES = $(libveejayui_la_SOURCES) $(veejayui_SOURCES) - -srcdir = @srcdir@ -top_srcdir = @top_srcdir@ -VPATH = @srcdir@ -pkgdatadir = $(datadir)/@PACKAGE@ -pkglibdir = $(libdir)/@PACKAGE@ -pkgincludedir = $(includedir)/@PACKAGE@ -top_builddir = .. -am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd -INSTALL = @INSTALL@ -install_sh_DATA = $(install_sh) -c -m 644 -install_sh_PROGRAM = $(install_sh) -c -install_sh_SCRIPT = $(install_sh) -c -INSTALL_HEADER = $(INSTALL_DATA) -transform = $(program_transform_name) -NORMAL_INSTALL = : -PRE_INSTALL = : -POST_INSTALL = : -NORMAL_UNINSTALL = : -PRE_UNINSTALL = : -POST_UNINSTALL = : -build_triplet = @build@ -host_triplet = @host@ -target_triplet = @target@ -bin_PROGRAMS = $(am__EXEEXT_1) -subdir = ui -DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in -ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 -am__aclocal_m4_deps = $(top_srcdir)/configure.ac -am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ - $(ACLOCAL_M4) -mkinstalldirs = $(install_sh) -d -CONFIG_HEADER = $(top_builddir)/config.h -CONFIG_CLEAN_FILES = -am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; -am__vpath_adj = case $$p in \ - $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ - *) f=$$p;; \ - esac; -am__strip_dir = `echo $$p | sed -e 's|^.*/||'`; -am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(bindir)" -libLTLIBRARIES_INSTALL = $(INSTALL) -LTLIBRARIES = $(lib_LTLIBRARIES) -libveejayui_la_DEPENDENCIES = / -am_libveejayui_la_OBJECTS = buffer.lo concretebuilder.lo builder.lo \ - samplebank.lo anim.lo anim_ui.lo director.lo uiosc.lo -libveejayui_la_OBJECTS = $(am_libveejayui_la_OBJECTS) -am__EXEEXT_1 = veejayui$(EXEEXT) -binPROGRAMS_INSTALL = $(INSTALL_PROGRAM) -PROGRAMS = $(bin_PROGRAMS) -am_veejayui_OBJECTS = testui.$(OBJEXT) -veejayui_OBJECTS = $(am_veejayui_OBJECTS) -am__DEPENDENCIES_1 = -veejayui_DEPENDENCIES = libveejayui.la $(am__DEPENDENCIES_1) \ - $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ - $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) -DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) -depcomp = $(SHELL) $(top_srcdir)/depcomp -am__depfiles_maybe = depfiles -COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ - $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -LTCOMPILE = $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) \ - $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ - $(AM_CFLAGS) $(CFLAGS) -CCLD = $(CC) -LINK = $(LIBTOOL) --tag=CC --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ - $(AM_LDFLAGS) $(LDFLAGS) -o $@ -SOURCES = $(libveejayui_la_SOURCES) $(veejayui_SOURCES) -DIST_SOURCES = $(libveejayui_la_SOURCES) $(veejayui_SOURCES) -ETAGS = etags -CTAGS = ctags -DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) -ACLOCAL = @ACLOCAL@ -ALTIVEC_CFLAGS = @ALTIVEC_CFLAGS@ -AMDEP_FALSE = @AMDEP_FALSE@ -AMDEP_TRUE = @AMDEP_TRUE@ -AMTAR = @AMTAR@ -AR = @AR@ -AS = @AS@ -ASFLAGS = @ASFLAGS@ -AUTOCONF = @AUTOCONF@ -AUTOHEADER = @AUTOHEADER@ -AUTOMAKE = @AUTOMAKE@ -AWK = @AWK@ -CC = @CC@ -CCAS = @CCAS@ -CCASFLAGS = @CCASFLAGS@ -CCDEPMODE = @CCDEPMODE@ -CFLAGS = @CFLAGS@ -CPP = @CPP@ -CPPFLAGS = @CPPFLAGS@ -CXX = @CXX@ -CXXCPP = @CXXCPP@ -CXXDEPMODE = @CXXDEPMODE@ -CXXFLAGS = @CXXFLAGS@ -CYGPATH_W = @CYGPATH_W@ -DEFS = @DEFS@ -DEPDIR = @DEPDIR@ -ECHO = @ECHO@ -ECHO_C = @ECHO_C@ -ECHO_N = @ECHO_N@ -ECHO_T = @ECHO_T@ -EGREP = @EGREP@ -EXEEXT = @EXEEXT@ -F77 = @F77@ -FFLAGS = @FFLAGS@ -FFMPEG_AVCODEC_CFLAGS = @FFMPEG_AVCODEC_CFLAGS@ -FFMPEG_AVCODEC_LIBS = @FFMPEG_AVCODEC_LIBS@ -FFMPEG_AVFORMAT_CFLAGS = @FFMPEG_AVFORMAT_CFLAGS@ -FFMPEG_AVFORMAT_LIBS = @FFMPEG_AVFORMAT_LIBS@ -GLADE_CFLAGS = @GLADE_CFLAGS@ -GLADE_LIBS = @GLADE_LIBS@ -GLIB_CFLAGS = @GLIB_CFLAGS@ -GLIB_CONFIG = @GLIB_CONFIG@ -GLIB_LIBS = @GLIB_LIBS@ -GL_CFLAGS = @GL_CFLAGS@ -GL_LIBS = @GL_LIBS@ -GTK_CFLAGS = @GTK_CFLAGS@ -GTK_LIBS = @GTK_LIBS@ -HAVE_ALTIVEC_FALSE = @HAVE_ALTIVEC_FALSE@ -HAVE_ALTIVEC_TRUE = @HAVE_ALTIVEC_TRUE@ -HAVE_ASM_MMX2_FALSE = @HAVE_ASM_MMX2_FALSE@ -HAVE_ASM_MMX2_TRUE = @HAVE_ASM_MMX2_TRUE@ -HAVE_ASM_MMX_FALSE = @HAVE_ASM_MMX_FALSE@ -HAVE_ASM_MMX_TRUE = @HAVE_ASM_MMX_TRUE@ -HAVE_ASM_NASM_FALSE = @HAVE_ASM_NASM_FALSE@ -HAVE_ASM_NASM_TRUE = @HAVE_ASM_NASM_TRUE@ -HAVE_ASM_SSE2_FALSE = @HAVE_ASM_SSE2_FALSE@ -HAVE_ASM_SSE2_TRUE = @HAVE_ASM_SSE2_TRUE@ -HAVE_ASM_SSE_FALSE = @HAVE_ASM_SSE_FALSE@ -HAVE_ASM_SSE_TRUE = @HAVE_ASM_SSE_TRUE@ -HAVE_DL_DLOPEN_FALSE = @HAVE_DL_DLOPEN_FALSE@ -HAVE_DL_DLOPEN_TRUE = @HAVE_DL_DLOPEN_TRUE@ -HAVE_JACK_FALSE = @HAVE_JACK_FALSE@ -HAVE_JACK_TRUE = @HAVE_JACK_TRUE@ -HAVE_MMX2_FALSE = @HAVE_MMX2_FALSE@ -HAVE_MMX2_TRUE = @HAVE_MMX2_TRUE@ -HAVE_MMX_FALSE = @HAVE_MMX_FALSE@ -HAVE_MMX_TRUE = @HAVE_MMX_TRUE@ -HAVE_PPCCPU_FALSE = @HAVE_PPCCPU_FALSE@ -HAVE_PPCCPU_TRUE = @HAVE_PPCCPU_TRUE@ -HAVE_SDL_FALSE = @HAVE_SDL_FALSE@ -HAVE_SDL_TRUE = @HAVE_SDL_TRUE@ -HAVE_SSE2_FALSE = @HAVE_SSE2_FALSE@ -HAVE_SSE2_TRUE = @HAVE_SSE2_TRUE@ -HAVE_SSE_FALSE = @HAVE_SSE_FALSE@ -HAVE_SSE_TRUE = @HAVE_SSE_TRUE@ -HAVE_V4L_FALSE = @HAVE_V4L_FALSE@ -HAVE_V4L_TRUE = @HAVE_V4L_TRUE@ -HAVE_X86CPU_FALSE = @HAVE_X86CPU_FALSE@ -HAVE_X86CPU_TRUE = @HAVE_X86CPU_TRUE@ -HAVE_XML2_FALSE = @HAVE_XML2_FALSE@ -HAVE_XML2_TRUE = @HAVE_XML2_TRUE@ -INSTALL_DATA = @INSTALL_DATA@ -INSTALL_PROGRAM = @INSTALL_PROGRAM@ -INSTALL_SCRIPT = @INSTALL_SCRIPT@ -INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ -JACK_CFLAGS = @JACK_CFLAGS@ -JACK_LIBS = @JACK_LIBS@ -LDFLAGS = @LDFLAGS@ -LIBDV_CFLAGS = @LIBDV_CFLAGS@ -LIBDV_LIBS = @LIBDV_LIBS@ -LIBGETOPT_LIB = @LIBGETOPT_LIB@ -LIBLO_CFLAGS = @LIBLO_CFLAGS@ -LIBLO_LIBS = @LIBLO_LIBS@ -LIBM_LIBS = @LIBM_LIBS@ -LIBOBJS = @LIBOBJS@ -LIBS = @LIBS@ -LIBTOOL = @LIBTOOL@ -LN_S = @LN_S@ -LTLIBOBJS = @LTLIBOBJS@ -LT_AGE = @LT_AGE@ -LT_CURRENT = @LT_CURRENT@ -LT_RELEASE = @LT_RELEASE@ -LT_REVISION = @LT_REVISION@ -MAINT = @MAINT@ -MAINTAINER_MODE_FALSE = @MAINTAINER_MODE_FALSE@ -MAINTAINER_MODE_TRUE = @MAINTAINER_MODE_TRUE@ -MAKEINFO = @MAKEINFO@ -MJPEGTOOLS_CFLAGS = @MJPEGTOOLS_CFLAGS@ -MJPEGTOOLS_LIBS = @MJPEGTOOLS_LIBS@ -OBJEXT = @OBJEXT@ -PACKAGE = @PACKAGE@ -PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ -PACKAGE_NAME = @PACKAGE_NAME@ -PACKAGE_STRING = @PACKAGE_STRING@ -PACKAGE_TARNAME = @PACKAGE_TARNAME@ -PACKAGE_VERSION = @PACKAGE_VERSION@ -PATH_SEPARATOR = @PATH_SEPARATOR@ -PKG_CONFIG = @PKG_CONFIG@ -PROGRAM_NOPIC = @PROGRAM_NOPIC@ -PTHREAD_LIBS = @PTHREAD_LIBS@ -RANLIB = @RANLIB@ -SAMPLERATE_CFLAGS = @SAMPLERATE_CFLAGS@ -SAMPLERATE_LIBS = @SAMPLERATE_LIBS@ -SDL_CFLAGS = @SDL_CFLAGS@ -SDL_CONFIG = @SDL_CONFIG@ -SDL_LIBS = @SDL_LIBS@ -SET_MAKE = @SET_MAKE@ -SHELL = @SHELL@ -STRIP = @STRIP@ -SUPPORT_READ_DV2_FALSE = @SUPPORT_READ_DV2_FALSE@ -SUPPORT_READ_DV2_TRUE = @SUPPORT_READ_DV2_TRUE@ -UNICAP_CFLAGS = @UNICAP_CFLAGS@ -UNICAP_LIBS = @UNICAP_LIBS@ -V4LCONF_LIBS = @V4LCONF_LIBS@ -VERSION = @VERSION@ -XML2_CONFIG = @XML2_CONFIG@ -XML_CPPFLAGS = @XML_CPPFLAGS@ -XML_LIBS = @XML_LIBS@ -ac_ct_AR = @ac_ct_AR@ -ac_ct_CC = @ac_ct_CC@ -ac_ct_CXX = @ac_ct_CXX@ -ac_ct_F77 = @ac_ct_F77@ -ac_ct_RANLIB = @ac_ct_RANLIB@ -ac_ct_STRIP = @ac_ct_STRIP@ -ac_pt_PKG_CONFIG = @ac_pt_PKG_CONFIG@ -am__fastdepCC_FALSE = @am__fastdepCC_FALSE@ -am__fastdepCC_TRUE = @am__fastdepCC_TRUE@ -am__fastdepCXX_FALSE = @am__fastdepCXX_FALSE@ -am__fastdepCXX_TRUE = @am__fastdepCXX_TRUE@ -am__include = @am__include@ -am__leading_dot = @am__leading_dot@ -am__quote = @am__quote@ -am__tar = @am__tar@ -am__untar = @am__untar@ -bindir = @bindir@ -build = @build@ -build_alias = @build_alias@ -build_cpu = @build_cpu@ -build_os = @build_os@ -build_vendor = @build_vendor@ -datadir = @datadir@ -exec_prefix = @exec_prefix@ -host = @host@ -host_alias = @host_alias@ -host_cpu = @host_cpu@ -host_os = @host_os@ -host_vendor = @host_vendor@ -includedir = @includedir@ -infodir = @infodir@ -install_sh = @install_sh@ -libdir = @libdir@ -libexecdir = @libexecdir@ -localstatedir = @localstatedir@ -mandir = @mandir@ -mkdir_p = @mkdir_p@ -oldincludedir = @oldincludedir@ -prefix = @prefix@ -program_transform_name = @program_transform_name@ -sbindir = @sbindir@ -sharedstatedir = @sharedstatedir@ -sysconfdir = @sysconfdir@ -target = @target@ -target_alias = @target_alias@ -target_cpu = @target_cpu@ -target_os = @target_os@ -target_vendor = @target_vendor@ -MAINTAINERCLEANFILES = Makefile.in -INCLUDES = -I$(top_srcdir) -I$(includedir) \ - -DG_LOG_DOMAIN=\"veejayui\" -DVEEJAY_VERSION=\"$(VERSION)\" \ - -I /usr/X11R6/include \ - -I$(top_srcdir)/libhash \ - -I$(top_srcdir)/libvjmem \ - -I$(top_srcdir)/libvjmsg \ - -I$(top_srcdir)/libvevo \ - ${XML_CFLAGS} \ - ${LIBLO_CFLAGS} \ - ${GLADE_CFLAGS} \ - ${GTK_CFLAGS} \ - ${GLIB_CFLAGS} - -UI_LIB_FILE = libveejayui.la -lib_LTLIBRARIES = $(UI_LIB_FILE) -UI_ALL_LIB_OPTS = \ - -version-info $(LT_AGE):$(LT_REVISION):$(LT_AGE) \ - -release $(LT_RELEASE) \ - -export-dynamic - -libveejayui_la_SOURCES = buffer.c concretebuilder.c builder.c samplebank.c anim.c anim_ui.c director.c uiosc.c -libveejayui_la_LDFLAGS = $(UI_ALL_LIB_OPTS ) -libveejayui_la_LIBADD = -L$(top_builddir)/libhash / -lhash \ - -L$(top_builddir)/libvjmsg -lvjmsg \ - -L$(top_builddir)/libvjmem/ -lvjmem \ - -L$(top_builddir)/libvevo -lvevo - -UI_BIN = veejayui -veejayui_SOURCES = testui.c -veejayui_LDADD = libveejayui.la @LIBGETOPT_LIB@ \ - ${XML_LIBS} ${LIBLO_LIBS} ${GLADE_LIBS} ${GTK_LIBS} ${GLIB_LIBS} -lgthread-2.0 - -all: all-am - -.SUFFIXES: -.SUFFIXES: .c .lo .o .obj -$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) - @for dep in $?; do \ - case '$(am__configure_deps)' in \ - *$$dep*) \ - cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ - && exit 0; \ - exit 1;; \ - esac; \ - done; \ - echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu ui/Makefile'; \ - cd $(top_srcdir) && \ - $(AUTOMAKE) --gnu ui/Makefile -.PRECIOUS: Makefile -Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status - @case '$?' in \ - *config.status*) \ - cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ - *) \ - echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ - cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ - esac; - -$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) - cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh - -$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) - cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh -$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) - cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh -install-libLTLIBRARIES: $(lib_LTLIBRARIES) - @$(NORMAL_INSTALL) - test -z "$(libdir)" || $(mkdir_p) "$(DESTDIR)$(libdir)" - @list='$(lib_LTLIBRARIES)'; for p in $$list; do \ - if test -f $$p; then \ - f=$(am__strip_dir) \ - echo " $(LIBTOOL) --mode=install $(libLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) '$$p' '$(DESTDIR)$(libdir)/$$f'"; \ - $(LIBTOOL) --mode=install $(libLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) "$$p" "$(DESTDIR)$(libdir)/$$f"; \ - else :; fi; \ - done - -uninstall-libLTLIBRARIES: - @$(NORMAL_UNINSTALL) - @set -x; list='$(lib_LTLIBRARIES)'; for p in $$list; do \ - p=$(am__strip_dir) \ - echo " $(LIBTOOL) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$p'"; \ - $(LIBTOOL) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$p"; \ - done - -clean-libLTLIBRARIES: - -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) - @list='$(lib_LTLIBRARIES)'; for p in $$list; do \ - dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ - test "$$dir" != "$$p" || dir=.; \ - echo "rm -f \"$${dir}/so_locations\""; \ - rm -f "$${dir}/so_locations"; \ - done -libveejayui.la: $(libveejayui_la_OBJECTS) $(libveejayui_la_DEPENDENCIES) - $(LINK) -rpath $(libdir) $(libveejayui_la_LDFLAGS) $(libveejayui_la_OBJECTS) $(libveejayui_la_LIBADD) $(LIBS) -install-binPROGRAMS: $(bin_PROGRAMS) - @$(NORMAL_INSTALL) - test -z "$(bindir)" || $(mkdir_p) "$(DESTDIR)$(bindir)" - @list='$(bin_PROGRAMS)'; for p in $$list; do \ - p1=`echo $$p|sed 's/$(EXEEXT)$$//'`; \ - if test -f $$p \ - || test -f $$p1 \ - ; then \ - f=`echo "$$p1" | sed 's,^.*/,,;$(transform);s/$$/$(EXEEXT)/'`; \ - echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) --mode=install $(binPROGRAMS_INSTALL) '$$p' '$(DESTDIR)$(bindir)/$$f'"; \ - $(INSTALL_PROGRAM_ENV) $(LIBTOOL) --mode=install $(binPROGRAMS_INSTALL) "$$p" "$(DESTDIR)$(bindir)/$$f" || exit 1; \ - else :; fi; \ - done - -uninstall-binPROGRAMS: - @$(NORMAL_UNINSTALL) - @list='$(bin_PROGRAMS)'; for p in $$list; do \ - f=`echo "$$p" | sed 's,^.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/'`; \ - echo " rm -f '$(DESTDIR)$(bindir)/$$f'"; \ - rm -f "$(DESTDIR)$(bindir)/$$f"; \ - done - -clean-binPROGRAMS: - @list='$(bin_PROGRAMS)'; for p in $$list; do \ - f=`echo $$p|sed 's/$(EXEEXT)$$//'`; \ - echo " rm -f $$p $$f"; \ - rm -f $$p $$f ; \ - done -veejayui$(EXEEXT): $(veejayui_OBJECTS) $(veejayui_DEPENDENCIES) - @rm -f veejayui$(EXEEXT) - $(LINK) $(veejayui_LDFLAGS) $(veejayui_OBJECTS) $(veejayui_LDADD) $(LIBS) - -mostlyclean-compile: - -rm -f *.$(OBJEXT) - -distclean-compile: - -rm -f *.tab.c - -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/anim.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/anim_ui.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/buffer.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/builder.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/concretebuilder.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/director.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/samplebank.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/testui.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/uiosc.Plo@am__quote@ - -.c.o: -@am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \ -@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(COMPILE) -c $< - -.c.obj: -@am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ `$(CYGPATH_W) '$<'`; \ -@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` - -.c.lo: -@am__fastdepCC_TRUE@ if $(LTCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \ -@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Plo"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< - -mostlyclean-libtool: - -rm -f *.lo - -clean-libtool: - -rm -rf .libs _libs - -distclean-libtool: - -rm -f libtool -uninstall-info-am: - -ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) - list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ - unique=`for i in $$list; do \ - if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ - done | \ - $(AWK) ' { files[$$0] = 1; } \ - END { for (i in files) print i; }'`; \ - mkid -fID $$unique -tags: TAGS - -TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ - $(TAGS_FILES) $(LISP) - tags=; \ - here=`pwd`; \ - list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ - unique=`for i in $$list; do \ - if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ - done | \ - $(AWK) ' { files[$$0] = 1; } \ - END { for (i in files) print i; }'`; \ - if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \ - test -n "$$unique" || unique=$$empty_fix; \ - $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ - $$tags $$unique; \ - fi -ctags: CTAGS -CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ - $(TAGS_FILES) $(LISP) - tags=; \ - here=`pwd`; \ - list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ - unique=`for i in $$list; do \ - if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ - done | \ - $(AWK) ' { files[$$0] = 1; } \ - END { for (i in files) print i; }'`; \ - test -z "$(CTAGS_ARGS)$$tags$$unique" \ - || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ - $$tags $$unique - -GTAGS: - here=`$(am__cd) $(top_builddir) && pwd` \ - && cd $(top_srcdir) \ - && gtags -i $(GTAGS_ARGS) $$here - -distclean-tags: - -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags - -distdir: $(DISTFILES) - @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ - topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \ - list='$(DISTFILES)'; for file in $$list; do \ - case $$file in \ - $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ - $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ - esac; \ - if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ - dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ - if test "$$dir" != "$$file" && test "$$dir" != "."; then \ - dir="/$$dir"; \ - $(mkdir_p) "$(distdir)$$dir"; \ - else \ - dir=''; \ - fi; \ - if test -d $$d/$$file; then \ - if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ - cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ - fi; \ - cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ - else \ - test -f $(distdir)/$$file \ - || cp -p $$d/$$file $(distdir)/$$file \ - || exit 1; \ - fi; \ - done -check-am: all-am -check: check-am -all-am: Makefile $(LTLIBRARIES) $(PROGRAMS) -install-binPROGRAMS: install-libLTLIBRARIES - -installdirs: - for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(bindir)"; do \ - test -z "$$dir" || $(mkdir_p) "$$dir"; \ - done -install: install-am -install-exec: install-exec-am -install-data: install-data-am -uninstall: uninstall-am - -install-am: all-am - @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am - -installcheck: installcheck-am -install-strip: - $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ - install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ - `test -z '$(STRIP)' || \ - echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install -mostlyclean-generic: - -clean-generic: - -distclean-generic: - -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) - -maintainer-clean-generic: - @echo "This command is intended for maintainers to use" - @echo "it deletes files that may require special tools to rebuild." - -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) -clean: clean-am - -clean-am: clean-binPROGRAMS clean-generic clean-libLTLIBRARIES \ - clean-libtool mostlyclean-am - -distclean: distclean-am - -rm -rf ./$(DEPDIR) - -rm -f Makefile -distclean-am: clean-am distclean-compile distclean-generic \ - distclean-libtool distclean-tags - -dvi: dvi-am - -dvi-am: - -html: html-am - -info: info-am - -info-am: - -install-data-am: - -install-exec-am: install-binPROGRAMS install-libLTLIBRARIES - -install-info: install-info-am - -install-man: - -installcheck-am: - -maintainer-clean: maintainer-clean-am - -rm -rf ./$(DEPDIR) - -rm -f Makefile -maintainer-clean-am: distclean-am maintainer-clean-generic - -mostlyclean: mostlyclean-am - -mostlyclean-am: mostlyclean-compile mostlyclean-generic \ - mostlyclean-libtool - -pdf: pdf-am - -pdf-am: - -ps: ps-am - -ps-am: - -uninstall-am: uninstall-binPROGRAMS uninstall-info-am \ - uninstall-libLTLIBRARIES - -.PHONY: CTAGS GTAGS all all-am check check-am clean clean-binPROGRAMS \ - clean-generic clean-libLTLIBRARIES clean-libtool ctags \ - distclean distclean-compile distclean-generic \ - distclean-libtool distclean-tags distdir dvi dvi-am html \ - html-am info info-am install install-am install-binPROGRAMS \ - install-data install-data-am install-exec install-exec-am \ - install-info install-info-am install-libLTLIBRARIES \ - install-man install-strip installcheck installcheck-am \ - installdirs maintainer-clean maintainer-clean-generic \ - mostlyclean mostlyclean-compile mostlyclean-generic \ - mostlyclean-libtool pdf pdf-am ps ps-am tags uninstall \ - uninstall-am uninstall-binPROGRAMS uninstall-info-am \ - uninstall-libLTLIBRARIES - -# Tell versions [3.59,3.63) of GNU make to not export all variables. -# Otherwise a system limit (for SysV at least) may be exceeded. -.NOEXPORT: diff --git a/veejay-ng/veejay/Makefile.am b/veejay-ng/veejay/Makefile.am index 34da8615..e9b8220d 100644 --- a/veejay-ng/veejay/Makefile.am +++ b/veejay-ng/veejay/Makefile.am @@ -18,8 +18,8 @@ INCLUDES = -I$(top_srcdir) -I$(includedir) \ -I$(top_srcdir)/libsamplerec \ -I$(top_srcdir)/libvevo \ $(FFMPEG_CFLAGS)\ - ${XML_CFLAGS} ${DV_FLAGS} ${X_CFLAGS} ${XML_CPPFLAGS} \ - ${PTHREAD_CFLAGS} ${MJPEGTOOLS_CFLAGS} ${GL_CFLAGS} ${SDL_CFLAGS} ${LIBLO_CFLAGS} + ${XML_CFLAGS} ${DV_FLAGS} ${X_CFLAGS} ${XML_CPPFLAGS} ${LIBQUICKTIME_CFLAGS} \ + ${PTHREAD_CFLAGS} ${MJPEGTOOLS_CFLAGS} ${GL_CFLAGS} ${SDL_CFLAGS} ${LIBLO_CFLAGS} VEEJAY_LIB_FILE = libveejayng.la @@ -68,5 +68,5 @@ bin_PROGRAMS = $(VEEJAY_BIN) veejayng_SOURCES = veejay.c veejayng_LDADD = libveejayng.la @LIBGETOPT_LIB@ ${FFMPEG_AVCODEC_LIBS} ${FFMPEG_AVFORMAT_LIBS} \ - ${PTHREAD_LIBS} ${XML_LIBS} ${LIBDV_LIBS} ${GL_LIBS} \ + ${PTHREAD_LIBS} ${XML_LIBS} ${LIBDV_LIBS} ${GL_LIBS} ${LIBQUICKTIME_LIBS} \ ${MJPEGTOOLS_LIBS} ${UNICAP_LIBS} ${LIBM_LIBS} ${SDL_LIBS} ${LIBLO_LIBS} diff --git a/veejay-ng/veejay/defs.h b/veejay-ng/veejay/defs.h index 8ad826d5..2441ac21 100644 --- a/veejay-ng/veejay/defs.h +++ b/veejay-ng/veejay/defs.h @@ -50,6 +50,9 @@ typedef struct AFrame_t #define FMT_422 1 #define FMT_444 2 #define FMT_411 3 +#define FMT_420F 10 +#define FMT_422F 11 +#define FMT_444F 12 #define NO_AUDIO 0 #define AUDIO_PLAY 1 diff --git a/veejay-ng/veejay/liblavplayvj.c b/veejay-ng/veejay/liblavplayvj.c index 2d2bc7b2..a13d4ea4 100644 --- a/veejay-ng/veejay/liblavplayvj.c +++ b/veejay-ng/veejay/liblavplayvj.c @@ -316,14 +316,14 @@ int veejay_init_project_from_args( veejay_t *info, int w, int h, float fps, int veejay_msg(2, "\tvideo settings: %d x %d, @%2.2f in %s", svit->w,svit->h,svit->fps, (svit->norm ? "NTSC" :"PAL") ); veejay_msg(2, "\taudio settings: %ld Hz, %d bits, %d channels, %d bps", svit->rate, svit->bits,svit->chans, svit->bps ); + veejay_msg(2, "\toutput pixel format: %d", fmt); info->video_info = (void*) svit; #ifdef STRICT_CHECKING assert( info->video_info != NULL ); #endif info->use_display = display; - - vj_el_init(); + vj_el_init(fmt); if(prepare_cache_line( 10, 3 )) { @@ -1244,6 +1244,8 @@ void veejay_add_client( veejay_t *info, char *uri ) void *veejay_get_osc_sender(veejay_t * info ) { + if(!info) + return NULL; void *sender = NULL; if(!info->current_client) return NULL; diff --git a/veejay-ng/vevosample/vevosample.c b/veejay-ng/vevosample/vevosample.c index 8c50de80..b2004907 100644 --- a/veejay-ng/vevosample/vevosample.c +++ b/veejay-ng/vevosample/vevosample.c @@ -348,7 +348,6 @@ int sample_get_run_id( void *info ) sample_runtime_data *srd = (sample_runtime_data*) info; return srd->primary_key; } - int sample_get_key_ptr( void *info ) { if(!info) @@ -368,6 +367,7 @@ int sample_get_key_ptr( void *info ) void sample_delete_ptr( void *info ) { sample_runtime_data *srd = (sample_runtime_data*) info; + //@ FIXME: get default channel configuratioe_data *srd = (sample_runtime_data*) info; #ifdef STRICT_CHECKING assert( info != NULL ); @@ -386,16 +386,11 @@ void sample_delete_ptr( void *info ) void *osc_space = NULL; error = vevo_property_get( srd->info_port, "HOST_osc",0,&osc_space ); -#ifdef STRICT_CHECKING - assert( error == VEVO_NO_ERROR ); -#endif - - veejay_osc_del_methods( srd->user_data, osc_space,srd->info_port ,srd); + if( error == VEVO_NO_ERROR ) + veejay_osc_del_methods( srd->user_data, osc_space,srd->info_port ,srd); -// sample_fx_clean_up( info, srd->user_data ); + sample_fx_clean_up( info, srd->user_data ); - sample_fx_chain_reset( info ); - sample_close( srd ); vevo_port_recursive_free( srd->info_port ); @@ -1221,8 +1216,8 @@ static void sample_ui_close_all( void *sample ) // { // sample_ui_fx_close( sample, i, srd->user_data ); // } - - sample_ui_close(sample); + if(srd->data) + sample_ui_close(sample); } @@ -1230,14 +1225,14 @@ static void sample_fx_entry_clean_up( void *sample, int id, void *user_data ) { sample_runtime_data *srd = (sample_runtime_data*) sample; fx_slot_t *slot = sample_get_fx_port_ptr( srd, id ); - +#ifdef STRICT_CHECKING + assert( srd->info_port != NULL ); +#endif if(slot->window) + { sample_ui_fx_close( sample, id, user_data ); - else - veejay_msg(0, "FX slot %d has no window, sample %d", id, - sample_get_key_ptr(sample) ); - if(slot->window) free(slot->window); + } if(slot->frame) free(slot->frame); @@ -1247,14 +1242,15 @@ static void sample_fx_entry_clean_up( void *sample, int id, void *user_data ) plug_deactivate( slot->fx_instance ); } - vevo_port_free( slot->in_values ); - vevo_port_free( slot->out_values ); - vevo_port_free( slot->out_channels ); + if( slot->in_values ) + vevo_port_free( slot->in_values ); + if( slot->out_values) + vevo_port_free( slot->out_values ); + if( slot->out_channels) + vevo_port_free( slot->out_channels ); if( slot->bind ) - { sample_reset_bind ( sample, slot ); - } free(slot);