Updated libtheora from 1.1 to 1.1.1, we kept the CMakeLists.txt

--HG--
branch : update-to-libtheora-1.1.1
This commit is contained in:
EntranceJew
2016-02-12 11:29:23 -05:00
parent cda9f55e33
commit be26fc29ae
340 changed files with 125491 additions and 51558 deletions
@@ -0,0 +1,121 @@
# Microsoft Developer Studio Project File - Name="dumpvid" - Package Owner=<4>
# Microsoft Developer Studio Generated Build File, Format Version 6.00
# ** DO NOT EDIT **
# TARGTYPE "Win32 (x86) Console Application" 0x0103
CFG=dumpvid - Win32 Debug
!MESSAGE This is not a valid makefile. To build this project using NMAKE,
!MESSAGE use the Export Makefile command and run
!MESSAGE
!MESSAGE NMAKE /f "dumpvid.mak".
!MESSAGE
!MESSAGE You can specify a configuration when running NMAKE
!MESSAGE by defining the macro CFG on the command line. For example:
!MESSAGE
!MESSAGE NMAKE /f "dumpvid.mak" CFG="dumpvid - Win32 Debug"
!MESSAGE
!MESSAGE Possible choices for configuration are:
!MESSAGE
!MESSAGE "dumpvid - Win32 Release" (based on "Win32 (x86) Console Application")
!MESSAGE "dumpvid - Win32 Debug" (based on "Win32 (x86) Console Application")
!MESSAGE
# Begin Project
# PROP AllowPerConfigDependencies 0
# PROP Scc_ProjName ""
# PROP Scc_LocalPath ""
CPP=cl.exe
RSC=rc.exe
!IF "$(CFG)" == "dumpvid - Win32 Release"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 0
# PROP BASE Output_Dir "Release"
# PROP BASE Intermediate_Dir "Release"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 0
# PROP Output_Dir "Release"
# PROP Intermediate_Dir "Release"
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /Yu"stdafx.h" /FD /c
# ADD CPP /nologo /MD /W3 /GX /O2 /I "..\..\..\include" /I "..\..\..\..\ogg\include" /I "..\wincompat" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /FD /c
# SUBTRACT CPP /YX /Yc /Yu
# ADD BASE RSC /l 0x409 /d "NDEBUG"
# ADD RSC /l 0x409 /d "NDEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib theora_static.lib ogg_static.lib /nologo /subsystem:console /machine:I386 /nodefaultlib:"LIBCMT" /out:"dump_vid.exe" /libpath:"..\..\Static_Release" /libpath:"..\..\..\..\ogg\win32\Static_Release" /libpath:"..\..\..\..\vorbis\win32\Vorbis_Static_Release" /libpath:"..\..\..\..\vorbis\win32\VorbisEnc_Static_Release"
!ELSEIF "$(CFG)" == "dumpvid - Win32 Debug"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 1
# PROP BASE Output_Dir "Debug"
# PROP BASE Intermediate_Dir "Debug"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 1
# PROP Output_Dir "Debug"
# PROP Intermediate_Dir "Debug"
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /Yu"stdafx.h" /FD /GZ /c
# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "..\..\..\include" /I "..\..\..\..\ogg\include" /I "..\wincompat" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /FR /FD /GZ /c
# SUBTRACT CPP /YX /Yc /Yu
# ADD BASE RSC /l 0x409 /d "_DEBUG"
# ADD RSC /l 0x409 /d "_DEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib theora_static_d.lib ogg_static_d.lib /nologo /subsystem:console /debug /machine:I386 /nodefaultlib:"LIBCD" /out:"dump_vid.exe" /pdbtype:sept /libpath:"..\..\Static_Debug" /libpath:"..\..\..\..\ogg\win32\Static_Debug" /libpath:"..\..\..\..\vorbis\win32\Vorbis_Static_Debug" /libpath:"..\..\..\..\vorbis\win32\VorbisEnc_Static_Debug"
# SUBTRACT LINK32 /nodefaultlib
!ENDIF
# Begin Target
# Name "dumpvid - Win32 Release"
# Name "dumpvid - Win32 Debug"
# Begin Group "Source Files"
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
# Begin Source File
SOURCE=..\..\..\examples\dump_video.c
# End Source File
# Begin Source File
SOURCE=..\wincompat\getopt.c
# End Source File
# Begin Source File
SOURCE=..\wincompat\getopt_long.c
# End Source File
# End Group
# Begin Group "Header Files"
# PROP Default_Filter "h;hpp;hxx;hm;inl"
# End Group
# Begin Group "Resource Files"
# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
# End Group
# Begin Group "library"
# PROP Default_Filter ""
# End Group
# Begin Source File
SOURCE=.\ReadMe.txt
# End Source File
# End Target
# End Project
@@ -0,0 +1,13 @@
05/30/03
Updated to use the common encoder_sample.c source in theora/examples.
05/23/03
Very simple port of the sample encoder for Windows, for testing.
Encoder options in the command line are not working, and the frame rate
of video needs to be set in code (like in the simple sample encoder.)
This example will be updated to a true Win32 app sometime in the future,
hope it is useful for basic testing now.
mauricio@xiph.org
@@ -0,0 +1,121 @@
# Microsoft Developer Studio Project File - Name="encoderwin" - Package Owner=<4>
# Microsoft Developer Studio Generated Build File, Format Version 6.00
# ** DO NOT EDIT **
# TARGTYPE "Win32 (x86) Console Application" 0x0103
CFG=encoderwin - Win32 Debug
!MESSAGE This is not a valid makefile. To build this project using NMAKE,
!MESSAGE use the Export Makefile command and run
!MESSAGE
!MESSAGE NMAKE /f "encoderwin.mak".
!MESSAGE
!MESSAGE You can specify a configuration when running NMAKE
!MESSAGE by defining the macro CFG on the command line. For example:
!MESSAGE
!MESSAGE NMAKE /f "encoderwin.mak" CFG="encoderwin - Win32 Debug"
!MESSAGE
!MESSAGE Possible choices for configuration are:
!MESSAGE
!MESSAGE "encoderwin - Win32 Release" (based on "Win32 (x86) Console Application")
!MESSAGE "encoderwin - Win32 Debug" (based on "Win32 (x86) Console Application")
!MESSAGE
# Begin Project
# PROP AllowPerConfigDependencies 0
# PROP Scc_ProjName ""
# PROP Scc_LocalPath ""
CPP=cl.exe
RSC=rc.exe
!IF "$(CFG)" == "encoderwin - Win32 Release"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 0
# PROP BASE Output_Dir "Release"
# PROP BASE Intermediate_Dir "Release"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 0
# PROP Output_Dir "Release"
# PROP Intermediate_Dir "Release"
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /Yu"stdafx.h" /FD /c
# ADD CPP /nologo /MD /W3 /GX /O2 /I "..\..\..\include" /I "..\..\..\..\vorbis\include" /I "..\..\..\..\ogg\include" /I "..\wincompat" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /FD /c
# SUBTRACT CPP /YX /Yc /Yu
# ADD BASE RSC /l 0x409 /d "NDEBUG"
# ADD RSC /l 0x409 /d "NDEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib theora_static.lib ogg_static.lib vorbis_static.lib vorbisenc_static.lib /nologo /subsystem:console /machine:I386 /nodefaultlib:"LIBCMT" /out:"encoderwin.exe" /libpath:"..\..\Static_Release" /libpath:"..\..\..\..\ogg\win32\Static_Release" /libpath:"..\..\..\..\vorbis\win32\Vorbis_Static_Release" /libpath:"..\..\..\..\vorbis\win32\VorbisEnc_Static_Release"
!ELSEIF "$(CFG)" == "encoderwin - Win32 Debug"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 1
# PROP BASE Output_Dir "Debug"
# PROP BASE Intermediate_Dir "Debug"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 1
# PROP Output_Dir "Debug"
# PROP Intermediate_Dir "Debug"
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /Yu"stdafx.h" /FD /GZ /c
# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "..\..\..\include" /I "..\..\..\..\vorbis\include" /I "..\..\..\..\ogg\include" /I "..\wincompat" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /FD /GZ /c
# SUBTRACT CPP /YX /Yc /Yu
# ADD BASE RSC /l 0x409 /d "_DEBUG"
# ADD RSC /l 0x409 /d "_DEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib theora_static_d.lib ogg_static_d.lib vorbis_static_d.lib vorbisenc_static_d.lib /nologo /subsystem:console /debug /machine:I386 /nodefaultlib:"LIBCD" /out:"encoderwin.exe" /pdbtype:sept /libpath:"..\..\Static_Debug" /libpath:"..\..\..\..\ogg\win32\Static_Debug" /libpath:"..\..\..\..\vorbis\win32\Vorbis_Static_Debug" /libpath:"..\..\..\..\vorbis\win32\VorbisEnc_Static_Debug"
# SUBTRACT LINK32 /nodefaultlib
!ENDIF
# Begin Target
# Name "encoderwin - Win32 Release"
# Name "encoderwin - Win32 Debug"
# Begin Group "Source Files"
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
# Begin Source File
SOURCE=..\..\..\examples\encoder_example.c
# End Source File
# Begin Source File
SOURCE=..\wincompat\getopt.c
# End Source File
# Begin Source File
SOURCE=..\wincompat\getopt_long.c
# End Source File
# End Group
# Begin Group "Header Files"
# PROP Default_Filter "h;hpp;hxx;hm;inl"
# End Group
# Begin Group "Resource Files"
# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
# End Group
# Begin Group "library"
# PROP Default_Filter ""
# End Group
# Begin Source File
SOURCE=.\ReadMe.txt
# End Source File
# End Target
# End Project
@@ -0,0 +1,82 @@
#include <stdio.h>
#include <stdlib.h>
#ifdef _WIN32
#include <windows.h>
#else
typedef long DWORD;
#endif
/*extremely crude app to dump vp3 frames from an avi file*/
/*filenames are hardcoded*/
#include "avilib.h"
int main(int argc, const char **argv)
{
FILE * f = fopen("outfile.vp3", "wb");
char * buffer;
int olength;
int length;
avi_t *avifile;
int chunksize;
int frame;
int frames;
int keyframegap = 0;
int maxkeyframegap = 0;
DWORD initialticks;
int framew = 0;
int frameh = 0;
double framerate = 0.0f;
double fps_numerator, fps_denominator;
avifile = AVI_open_input_file("vp31.avi", 1);
frames = AVI_video_frames(avifile);
framew = AVI_video_width(avifile);
frameh = AVI_video_height(avifile);
framerate = AVI_frame_rate(avifile);
chunksize = AVI_max_video_chunk(avifile);
/* avilib only reports the max video chunk size if the file has an
idx table. We fall back to an arbitrary limit otherwise. Better
would be just to handle the chunks dynamically */
if (chunksize <= 0) chunksize = 131072;
buffer = malloc(chunksize);
printf("Frames(%d) Video(%dx%d) %3.2f fps\n",frames,framew, frameh,framerate);
printf("Video Compressor: %s", AVI_video_compressor(avifile));
fps_denominator = 1000000.0F;
fps_numerator = framerate * fps_denominator;
sprintf(buffer,"AVI2VP31R W%d H%d F%.0f:%.0f Ip A0:0\n", framew, frameh, fps_numerator, fps_denominator);
fwrite(buffer, strlen(buffer), 1, f);
for (frame = 0; frame < frames;) {
int keyframe;
olength = length;
length = AVI_frame_size(avifile, frame++);
if( !length ) {
length = olength;
}
AVI_read_frame(avifile, (char *) buffer, &keyframe);
fwrite("FRAME\n", 6, 1, f);
fwrite(&length, sizeof(int), 1, f);
fwrite(&keyframe, sizeof(int), 1, f);
printf("Frame size(%d) IsKeyframe(%d)\n", length, keyframe);
fwrite(buffer, 1, length, f);
if (!keyframe){
keyframegap++;
} else {
if (keyframegap>maxkeyframegap) maxkeyframegap=keyframegap;
keyframegap = 0;
}
}
fclose(f);
printf("Max keyframegap (%d)\n", maxkeyframegap);
free(buffer);
exit(0);
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,309 @@
/*
* avilib.h
*
* Copyright (C) Thomas Östreich - June 2001
* multiple audio track support Copyright (C) 2002 Thomas Östreich
*
* Original code:
* Copyright (C) 1999 Rainer Johanni <Rainer@Johanni.de>
*
* This file is part of transcode, a linux 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.
*
*/
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <inttypes.h>
#include <limits.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#ifndef AVILIB_H
#define AVILIB_H
#define AVI_MAX_TRACKS 8
typedef struct
{
unsigned long key;
unsigned long pos;
unsigned long len;
} video_index_entry;
typedef struct
{
unsigned long pos;
unsigned long len;
unsigned long tot;
} audio_index_entry;
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 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 */
char audio_tag[4]; /* Tag of audio data */
long audio_posc; /* Audio position: chunk */
long audio_posb; /* Audio position: byte within chunk */
long a_codech_off; /* absolut offset of audio codec information */
long a_codecf_off; /* absolut offset of audio codec information */
audio_index_entry *audio_index;
} track_t;
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) */
unsigned long max_len; /* maximum video chunk present */
track_t track[AVI_MAX_TRACKS]; // up to AVI_MAX_TRACKS audio tracks supported
unsigned long pos; /* position in file */
long n_idx; /* number of index entries actually filled */
long max_idx; /* number of index entries actually allocated */
long v_codech_off; /* absolut offset of video codec (strh) info */
long v_codecf_off; /* absolut offset of video codec (strf) info */
unsigned char (*idx)[16]; /* index entries (AVI idx1 tag) */
video_index_entry *video_index;
unsigned long last_pos; /* Position of last frame written */
unsigned long last_len; /* Length of last frame written */
int must_use_index; /* Flag if frames are duplicated */
unsigned long movi_start;
int anum; // total number of audio tracks
int aptr; // current audio working track
} avi_t;
#define AVI_MODE_WRITE 0
#define AVI_MODE_READ 1
/* The error codes delivered by avi_open_input_file */
#define AVI_ERR_SIZELIM 1 /* The write of the data would exceed
the maximum size of the AVI file.
This is more a warning than an error
since the file may be closed safely */
#define AVI_ERR_OPEN 2 /* Error opening the AVI file - wrong path
name or file nor readable/writable */
#define AVI_ERR_READ 3 /* Error reading from AVI File */
#define AVI_ERR_WRITE 4 /* Error writing to AVI File,
disk full ??? */
#define AVI_ERR_WRITE_INDEX 5 /* Could not write index to AVI file
during close, file may still be
usable */
#define AVI_ERR_CLOSE 6 /* Could not write header to AVI file
or not truncate the file during close,
file is most probably corrupted */
#define AVI_ERR_NOT_PERM 7 /* Operation not permitted:
trying to read from a file open
for writing or vice versa */
#define AVI_ERR_NO_MEM 8 /* malloc failed */
#define AVI_ERR_NO_AVI 9 /* Not an AVI file */
#define AVI_ERR_NO_HDRL 10 /* AVI file has no has no header list,
corrupted ??? */
#define AVI_ERR_NO_MOVI 11 /* AVI file has no has no MOVI list,
corrupted ??? */
#define AVI_ERR_NO_VIDS 12 /* AVI file contains no video data */
#define AVI_ERR_NO_IDX 13 /* The file has been opened with
getIndex==0, but an operation has been
performed that needs an index */
/* Possible Audio formats */
#ifndef WAVE_FORMAT_PCM
#define WAVE_FORMAT_UNKNOWN (0x0000)
#define WAVE_FORMAT_PCM (0x0001)
#define WAVE_FORMAT_ADPCM (0x0002)
#define WAVE_FORMAT_IBM_CVSD (0x0005)
#define WAVE_FORMAT_ALAW (0x0006)
#define WAVE_FORMAT_MULAW (0x0007)
#define WAVE_FORMAT_OKI_ADPCM (0x0010)
#define WAVE_FORMAT_DVI_ADPCM (0x0011)
#define WAVE_FORMAT_DIGISTD (0x0015)
#define WAVE_FORMAT_DIGIFIX (0x0016)
#define WAVE_FORMAT_YAMAHA_ADPCM (0x0020)
#define WAVE_FORMAT_DSP_TRUESPEECH (0x0022)
#define WAVE_FORMAT_GSM610 (0x0031)
#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, char *compressor);
void AVI_set_audio(avi_t *AVI, int channels, long rate, int bits, int format, long mp3rate);
int AVI_write_frame(avi_t *AVI, char *data, long bytes, int keyframe);
int AVI_dup_frame(avi_t *AVI);
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);
long AVI_bytes_written(avi_t *AVI);
avi_t *AVI_open_input_file(char *filename, int getIndex);
avi_t *AVI_open_fd(int fd, int getIndex);
int avi_parse_input_file(avi_t *AVI, int getIndex);
long AVI_audio_mp3rate(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_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);
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_get_video_position(avi_t *AVI, long frame);
long AVI_read_frame(avi_t *AVI, char *vidbuf, int *keyframe);
int AVI_set_audio_position(avi_t *AVI, long byte);
int AVI_set_audio_bitrate(avi_t *AVI, long bitrate);
long AVI_read_audio(avi_t *AVI, char *audbuf, long bytes);
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(char *str);
char *AVI_strerror();
char *AVI_syserror();
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();
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);
struct riff_struct
{
unsigned char id[4]; /* RIFF */
unsigned long len;
unsigned char wave_id[4]; /* WAVE */
};
struct chunk_struct
{
unsigned char id[4];
unsigned long len;
};
struct common_struct
{
unsigned short wFormatTag;
unsigned short wChannels;
unsigned long dwSamplesPerSec;
unsigned long dwAvgBytesPerSec;
unsigned short wBlockAlign;
unsigned short wBitsPerSample; /* Only for PCM */
};
struct wave_header
{
struct riff_struct riff;
struct chunk_struct format;
struct common_struct common;
struct chunk_struct data;
};
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
@@ -0,0 +1,17 @@
Quick hack at a transcoder tool from VP3 to Theora
I actually built the avi2vp3 tool with codeWarrior, but it should compile under
VC as well. I have included a source avi file and the converted .vp3 output.
Output is a file with some header info matching YUVMPEG, and for each frame:
FRAME header block matching YUV2MPEG
long (Intel aligned) keyframeflag describing in frame is a keyframe
long (Intel aligned) fsize storing frame size in bytes
bytes[fsize] with binary frame data
The transcode tool is a modification of the current encoder. PUt it into the
win32/experimental subdirectory, and the paths should be correct. It produces
an apparently valid theora stream, but outputs garbage data. The code is packing
the binary frame data in a way that SHOULD work at least imo, but I am probably
missing some initialization issue (or vp3 is not transcodable to theora).
@@ -0,0 +1,121 @@
# Microsoft Developer Studio Project File - Name="transcoder" - Package Owner=<4>
# Microsoft Developer Studio Generated Build File, Format Version 6.00
# ** DO NOT EDIT **
# TARGTYPE "Win32 (x86) Console Application" 0x0103
CFG=transcoder - Win32 Debug
!MESSAGE This is not a valid makefile. To build this project using NMAKE,
!MESSAGE use the Export Makefile command and run
!MESSAGE
!MESSAGE NMAKE /f "transcoder.mak".
!MESSAGE
!MESSAGE You can specify a configuration when running NMAKE
!MESSAGE by defining the macro CFG on the command line. For example:
!MESSAGE
!MESSAGE NMAKE /f "transcoder.mak" CFG="transcoder - Win32 Debug"
!MESSAGE
!MESSAGE Possible choices for configuration are:
!MESSAGE
!MESSAGE "transcoder - Win32 Release" (based on "Win32 (x86) Console Application")
!MESSAGE "transcoder - Win32 Debug" (based on "Win32 (x86) Console Application")
!MESSAGE
# Begin Project
# PROP AllowPerConfigDependencies 0
# PROP Scc_ProjName ""
# PROP Scc_LocalPath ""
CPP=cl.exe
RSC=rc.exe
!IF "$(CFG)" == "transcoder - Win32 Release"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 0
# PROP BASE Output_Dir "Release"
# PROP BASE Intermediate_Dir "Release"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 0
# PROP Output_Dir "Release"
# PROP Intermediate_Dir "Release"
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /Yu"stdafx.h" /FD /c
# ADD CPP /nologo /MD /W3 /GX /O2 /I "..\..\..\include" /I "..\..\..\..\vorbis\include" /I "..\..\..\..\ogg\include" /I "..\wincompat" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /D GETOPT_API= /FD /c
# SUBTRACT CPP /YX /Yc /Yu
# ADD BASE RSC /l 0x409 /d "NDEBUG"
# ADD RSC /l 0x409 /d "NDEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib theora_static.lib ogg_static.lib vorbis_static.lib vorbisenc_static.lib /nologo /subsystem:console /machine:I386 /nodefaultlib:"LIBCMT" /out:"transcoder.exe" /libpath:"..\..\Static_Release" /libpath:"..\..\..\..\ogg\win32\Static_Release" /libpath:"..\..\..\..\vorbis\win32\Vorbis_Static_Release" /libpath:"..\..\..\..\vorbis\win32\VorbisEnc_Static_Release"
!ELSEIF "$(CFG)" == "transcoder - Win32 Debug"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 1
# PROP BASE Output_Dir "Debug"
# PROP BASE Intermediate_Dir "Debug"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 1
# PROP Output_Dir "Debug"
# PROP Intermediate_Dir "Debug"
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /Yu"stdafx.h" /FD /GZ /c
# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "..\..\..\include" /I "..\..\..\..\vorbis\include" /I "..\..\..\..\ogg\include" /I "..\wincompat" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /D GETOPT_API= /FD /GZ /c
# SUBTRACT CPP /YX /Yc /Yu
# ADD BASE RSC /l 0x409 /d "_DEBUG"
# ADD RSC /l 0x409 /d "_DEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib theora_static_d.lib ogg_static_d.lib vorbis_static_d.lib vorbisenc_static_d.lib /nologo /subsystem:console /debug /machine:I386 /nodefaultlib:"LIBCD" /out:"transcoder.exe" /pdbtype:sept /libpath:"..\..\Static_Debug" /libpath:"..\..\..\..\ogg\win32\Static_Debug" /libpath:"..\..\..\..\vorbis\win32\Vorbis_Static_Debug" /libpath:"..\..\..\..\vorbis\win32\VorbisEnc_Static_Debug"
# SUBTRACT LINK32 /nodefaultlib
!ENDIF
# Begin Target
# Name "transcoder - Win32 Release"
# Name "transcoder - Win32 Debug"
# Begin Group "Source Files"
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
# Begin Source File
SOURCE=..\wincompat\getopt.c
# End Source File
# Begin Source File
SOURCE=..\wincompat\getopt_long.c
# End Source File
# Begin Source File
SOURCE=.\transcoder_example.c
# End Source File
# End Group
# Begin Group "Header Files"
# PROP Default_Filter "h;hpp;hxx;hm;inl"
# End Group
# Begin Group "Resource Files"
# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
# End Group
# Begin Group "library"
# PROP Default_Filter ""
# End Group
# Begin Source File
SOURCE=.\ReadMe.txt
# End Source File
# End Target
# End Project
@@ -0,0 +1,926 @@
/********************************************************************
* *
* THIS FILE IS PART OF THE OggTheora SOFTWARE CODEC SOURCE CODE. *
* USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
* GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
* *
* THE Theora SOURCE CODE IS COPYRIGHT (C) 2002-2004 *
* by the Xiph.Org Foundation http://www.xiph.org/ *
* *
********************************************************************
function: example encoder application; makes an Ogg Theora/Vorbis
file from YUV4MPEG2 and WAV input
last mod: $Id: transcoder_example.c,v 1.4 2004/03/20 00:14:04 tterribe Exp $
********************************************************************/
#define _GNU_SOURCE
#define _REENTRANT
#define _LARGEFILE_SOURCE
#define _LARGEFILE64_SOURCE
#define _FILE_OFFSET_BITS 64
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <getopt.h>
#include <time.h>
#include <math.h>
#include "theora/theora.h"
#include "vorbis/codec.h"
#include "vorbis/vorbisenc.h"
#ifdef _WIN32
/*supply missing headers and functions to Win32. going to hell, I know*/
#include <io.h>
#include <fcntl.h>
static double rint(double x)
{
if (x < 0.0)
return (double)(int)(x - 0.5);
else
return (double)(int)(x + 0.5);
}
#endif
/*Copied from vorbis/sharedbook.c*/
static int _ilog(unsigned int v){
int ret=0;
while(v){
ret++;
v>>=1;
}
return(ret);
}
const char *optstring = "o:a:A:v:V:";
struct option options [] = {
{"output",required_argument,NULL,'o'},
{"audio-rate-target",required_argument,NULL,'A'},
{"video-rate-target",required_argument,NULL,'V'},
{"audio-quality",required_argument,NULL,'a'},
{"video-quality",required_argument,NULL,'v'},
{NULL,0,NULL,0}
};
typedef struct TC_INSTANCE {
ogg_uint32_t LastKeyFrame ;
ogg_int64_t KeyFrameCount;
int ThisIsFirstFrame;
int ThisIsKeyFrame;
ogg_uint32_t CurrentFrame;
ogg_int64_t granulepos;
int keyframe_granule_shift;
char * in_bytes;
long in_bytecount;
ogg_uint32_t fps_denominator;
ogg_uint32_t fps_numerator;
oggpack_buffer opb_in;
oggpack_buffer opb_out;
} TC_INSTANCE;
/* You'll go to Hell for using globals. */
FILE *audio=NULL;
FILE *video=NULL;
int audio_ch=0;
int audio_hz=0;
float audio_q=.1;
int audio_r=-1;
int video_x=0;
int video_y=0;
int frame_x=0;
int frame_y=0;
int frame_x_offset=0;
int frame_y_offset=0;
int video_hzn=0;
int video_hzd=0;
int video_an=0;
int video_ad=0;
int video_r=-1;
int video_q=16;
char *vp3frame[2];
int framebytecount[2];
int frameiskey[2];
ogg_page audiopage;
ogg_page videopage;
static void usage(void){
fprintf(stderr,
"Usage: encoder_example [options] [audio_file] video_file\n\n"
"Options: \n\n"
" -o --output <filename.ogv> file name for encoded output;\n"
" If this option is not given, the\n"
" compressed data is sent to stdout.\n\n"
" -A --audio-rate-target <n> bitrate target for Vorbis audio;\n"
" use -a and not -A if at all possible,\n"
" as -a gives higher quality for a given\n"
" bitrate.\n\n"
" -V --video-rate-target <n> bitrate target for Theora video\n\n"
" -a --audio-quality <n> Vorbis quality selector from -1 to 10\n"
" (-1 yields smallest files but lowest\n"
" fidelity; 10 yields highest fidelity\n"
" but large files. '2' is a reasonable\n"
" default).\n\n"
" -v --video-quality <n> Theora quality selector fro 0 to 10\n"
" (0 yields smallest files but lowest\n"
" video quality. 10 yields highest\n"
" fidelity but large files).\n\n"
"encoder_example accepts only uncompressed RIFF WAV format audio and\n"
"YUV4MPEG2 uncompressed video.\n\n");
exit(1);
}
static void id_file(char *f){
FILE *test;
unsigned char buffer[80];
int ret;
/* open it, look for magic */
if(!strcmp(f,"-")){
/* stdin */
test=stdin;
}else{
test=fopen(f,"rb");
if(!test){
fprintf(stderr,"Unable to open file %s.\n",f);
exit(1);
}
}
ret=fread(buffer,1,4,test);
if(ret<4){
fprintf(stderr,"EOF determining file type of file %s.\n",f);
exit(1);
}
if(!memcmp(buffer,"RIFF",4)){
/* possible WAV file */
if(audio){
/* umm, we already have one */
fprintf(stderr,"Multiple RIFF WAVE files specified on command line.\n");
exit(1);
}
/* Parse the rest of the header */
ret=fread(buffer,1,4,test);
ret=fread(buffer,1,4,test);
if(ret<4)goto riff_err;
if(!memcmp(buffer,"WAVE",4)){
while(!feof(test)){
ret=fread(buffer,1,4,test);
if(ret<4)goto riff_err;
if(!memcmp("fmt",buffer,3)){
/* OK, this is our audio specs chunk. Slurp it up. */
ret=fread(buffer,1,20,test);
if(ret<20)goto riff_err;
if(memcmp(buffer+4,"\001\000",2)){
fprintf(stderr,"The WAV file %s is in a compressed format; "
"can't read it.\n",f);
exit(1);
}
audio=test;
audio_ch=buffer[6]+(buffer[7]<<8);
audio_hz=buffer[8]+(buffer[9]<<8)+
(buffer[10]<<16)+(buffer[11]<<24);
if(buffer[18]+(buffer[19]<<8)!=16){
fprintf(stderr,"Can only read 16 bit WAV files for now.\n");
exit(1);
}
/* Now, align things to the beginning of the data */
/* Look for 'dataxxxx' */
while(!feof(test)){
ret=fread(buffer,1,4,test);
if(ret<4)goto riff_err;
if(!memcmp("data",buffer,4)){
/* We're there. Ignore the declared size for now. */
ret=fread(buffer,1,4,test);
if(ret<4)goto riff_err;
fprintf(stderr,"File %s is 16 bit %d channel %d Hz RIFF WAV audio.\n",
f,audio_ch,audio_hz);
return;
}
}
}
}
}
fprintf(stderr,"Couldn't find WAVE data in RIFF file %s.\n",f);
exit(1);
}
if(!memcmp(buffer,"AVI2",4)){
/* possible AVI2VP31 format file */
/* read until newline, or 80 cols, whichever happens first */
int i;
for(i=0;i<79;i++){
ret=fread(buffer+i,1,1,test);
if(ret<1)goto yuv_err;
if(buffer[i]=='\n')break;
}
if(i==79){
fprintf(stderr,"Error parsing %s header; not a VP31 raw frames file?\n",f);
}
buffer[i]='\0';
if(!memcmp(buffer,"VP31",4)){
char interlace;
if(video){
/* umm, we already have one */
fprintf(stderr,"Multiple video files specified on command line.\n");
exit(1);
}
if(buffer[4]!='R'){
fprintf(stderr,"Incorrect file ; VP31 raw frames required.\n");
}
ret=sscanf(buffer,"VP31R W%d H%d F%d:%d I%c A%d:%d",
&frame_x,&frame_y,&video_hzn,&video_hzd,&interlace,
&video_an,&video_ad);
if(ret<7){
fprintf(stderr,"Error parsing AVI2VP31R header in file %s.\n",f);
exit(1);
}
if(interlace!='p'){
fprintf(stderr,"Input video is interlaced; Theora handles only progressive scan\n");
exit(1);
}
video=test;
fprintf(stderr,"File %s is %dx%d %.02f fps VP31 video.\n",
f,frame_x,frame_y,(double)video_hzn/video_hzd);
return;
}
}
fprintf(stderr,"Input file %s is neither a WAV nor VP31 file.\n",f);
exit(1);
riff_err:
fprintf(stderr,"EOF parsing RIFF file %s.\n",f);
exit(1);
yuv_err:
fprintf(stderr,"EOF parsing VP31 file %s.\n",f);
exit(1);
}
int spinner=0;
char *spinascii="|/-\\";
void spinnit(void){
spinner++;
if(spinner==4)spinner=0;
fprintf(stderr,"\r%c",spinascii[spinner]);
}
int fetch_and_process_audio(FILE *audio,ogg_page *audiopage,
ogg_stream_state *vo,
vorbis_dsp_state *vd,
vorbis_block *vb,
int audioflag){
ogg_packet op;
int i,j;
while(audio && !audioflag){
/* process any audio already buffered */
spinnit();
if(ogg_stream_pageout(vo,audiopage)>0) return 1;
if(ogg_stream_eos(vo))return 0;
{
/* read and process more audio */
signed char readbuffer[4096];
int toread=4096/2/audio_ch;
int bytesread=fread(readbuffer,1,toread*2*audio_ch,audio);
int sampread=bytesread/2/audio_ch;
float **vorbis_buffer;
int count=0;
if(bytesread<=0){
/* end of file. this can be done implicitly, but it's
easier to see here in non-clever fashion. Tell the
library we're at end of stream so that it can handle the
last frame and mark end of stream in the output properly */
vorbis_analysis_wrote(vd,0);
}else{
vorbis_buffer=vorbis_analysis_buffer(vd,sampread);
/* uninterleave samples */
for(i=0;i<sampread;i++){
for(j=0;j<audio_ch;j++){
vorbis_buffer[j][i]=((readbuffer[count+1]<<8)|
(0x00ff&(int)readbuffer[count]))/32768.f;
count+=2;
}
}
vorbis_analysis_wrote(vd,sampread);
}
while(vorbis_analysis_blockout(vd,vb)==1){
/* analysis, assume we want to use bitrate management */
vorbis_analysis(vb,NULL);
vorbis_bitrate_addblock(vb);
/* weld packets into the bitstream */
while(vorbis_bitrate_flushpacket(vd,&op))
ogg_stream_packetin(vo,&op);
}
}
}
return audioflag;
}
int theora_transcode_packetout( TC_INSTANCE *ttc, int last_p, ogg_packet *op){
long bytes=ttc->in_bytecount;
if(!bytes)return(0);
op->packet=ttc->in_bytes;
op->bytes=bytes;
op->b_o_s=0;
op->e_o_s=last_p;
op->packetno=ttc->CurrentFrame;
op->granulepos=ttc->granulepos;
return 1;
}
void TranscodeKeyFrame(TC_INSTANCE *ttc){
/* Keep track of the total number of Key Frames Coded */
ttc->KeyFrameCount += 1;
ttc->LastKeyFrame = 1;
}
void TranscodeFrame(TC_INSTANCE *ttc){
ttc->LastKeyFrame++;
}
void TranscodeFirstFrame(TC_INSTANCE *ttc){
/* Keep track of the total number of Key Frames Coded. */
ttc->KeyFrameCount = 1;
ttc->LastKeyFrame = 1;
}
int theora_transcode_bufferin( TC_INSTANCE *ttc, int isKeyFrame, char * bytes, int bytecount){
/*transcode: record keyframe flag*/
ttc->ThisIsKeyFrame = isKeyFrame;
/* Special case for first frame */
if ( ttc->ThisIsFirstFrame ){
ttc->ThisIsFirstFrame = 0;
ttc->ThisIsKeyFrame = 0;
} else if ( ttc->ThisIsKeyFrame ) {
TranscodeKeyFrame(ttc);
ttc->ThisIsKeyFrame = 0;
} else {
/* Compress the frame. */
TranscodeFrame( ttc );
}
/*need to pack info here*/
{
int frame_type;
long total_bits;
long total_words;
int frac_bits;
oggpackB_readinit(&ttc->opb_in,bytes,bytecount);
oggpackB_reset(&ttc->opb_out);
/*Mark as video frame.*/
oggpackB_write(&ttc->opb_out,0,1);
/*Copy frame type.*/
frame_type=oggpackB_read1(&ttc->opb_in);
oggpackB_write(&ttc->opb_out,frame_type,1);
/*Skip an unused bit in the VP32 header.*/
oggpackB_adv1(&ttc->opb_in);
/*Copy Q multiplier.*/
oggpackB_write(&ttc->opb_out,oggpackB_read(&ttc->opb_in,6),6);
/*VP3 has no per-block Q multipliers*/
oggpackB_write(&ttc->opb_out,0,1);
/*If the frame is a base/key/golden frame, copy a few extra bits.*/
if(frame_type==0){
/*These 13 bits are not included in a Theora frame header.
They were 0's and VP3 version info in VP32.*/
oggpackB_adv(&ttc->opb_in,13);
/*Copy the key frame type and the spare configuration bits.*/
oggpackB_write(&ttc->opb_out,oggpackB_read(&ttc->opb_in,3),3);
}
/*Copy the rest of the bits over.*/
total_bits=bytecount*8-oggpack_bits(&ttc->opb_in);
frac_bits=(int)(total_bits&31);
if(frac_bits){
oggpackB_write(&ttc->opb_out,oggpackB_read(&ttc->opb_in,frac_bits),
frac_bits);
}
total_words=total_bits>>5;
while(total_words-->0){
oggpackB_write(&ttc->opb_out,oggpackB_read(&ttc->opb_in,32),32);
}
ttc->in_bytecount = oggpackB_bytes(&ttc->opb_out);
ttc->in_bytes = oggpackB_get_buffer(&ttc->opb_out);
}
/* Update stats variables. */
ttc->CurrentFrame++;
ttc->granulepos=
((ttc->CurrentFrame-ttc->LastKeyFrame-1)<<ttc->keyframe_granule_shift)+
ttc->LastKeyFrame-1;
return 0;
}
//static void _tp_writebuffer(oggpack_buffer *opb, const char *buf, const long len)
int theora_transcoder_init(theora_info * ti, TC_INSTANCE * ttc){
memset(ttc, 0, sizeof(*ttc));
ttc->granulepos = -1;
ttc->keyframe_granule_shift=_ilog(ti->keyframe_frequency_force-1);
ttc->LastKeyFrame = 0;
ttc->KeyFrameCount = 0;
ttc->ThisIsFirstFrame = 1;
ttc->ThisIsKeyFrame = 0;
ttc->CurrentFrame = 1;
ttc->in_bytes = 0;
ttc->in_bytecount = 0;
ttc->fps_denominator = ti->fps_denominator;
ttc->fps_numerator = ti->fps_numerator;
oggpackB_writeinit(&ttc->opb_out);
return 0;
}
int fetch_and_process_video(FILE *video,ogg_page *videopage,
ogg_stream_state *to,
TC_INSTANCE *ttc,
int videoflag){
/* You'll go to Hell for using static variables */
static int state=-1;
ogg_packet op;
int i;
int keyframeflag, framelength;
if(state==-1){
/* initialize the double frame buffer */
state=0;
}
/* is there a video page flushed? If not, work until there is. */
while(!videoflag){
spinnit();
if(ogg_stream_pageout(to,videopage)>0) return 1;
if(ogg_stream_eos(to)) return 0;
{
/* read and process more video */
/* video strategy reads one frame ahead so we know when we're
at end of stream and can mark last video frame as such
(vorbis audio has to flush one frame past last video frame
due to overlap and thus doesn't need this extra work */
/* have two frame buffers full (if possible) before
proceeding. after first pass and until eos, one will
always be full when we get here */
for(i=state;i<2;i++){
char c,frame[6];
int ret=fread(frame,1,6,video);
/* match and skip the frame header */
if(ret<6)break;
if(memcmp(frame,"FRAME",5)){
fprintf(stderr,"Loss of framing in VP31 input data\n");
exit(1);
}
if(frame[5]!='\n'){
int j;
for(j=0;j<79;j++)
if(fread(&c,1,1,video)&&c=='\n')break;
if(j==79){
fprintf(stderr,"Error parsing VP31 frame header\n");
exit(1);
}
}
/*read the length*/
ret=fread(&framelength, sizeof(int), 1, video);
/*read the keyframeflag*/
ret=fread(&keyframeflag, sizeof(int), 1, video);
vp3frame[i] = malloc(framelength);
framebytecount[i] = framelength;
frameiskey[i] = keyframeflag;
/* read the frame */
ret=fread((char *) vp3frame[i], sizeof(char), framelength, video);
if(ret!=framelength) break;
state++;
}
if(state<1){
/* can't get here unless VP31 stream has no video */
fprintf(stderr,"Video input contains no frames.\n");
exit(1);
}
/* Theora is a one-frame-in,one-frame-out system; submit a frame
for compression and pull out the packet */
//theora_encode_YUVin(td,&yuv);
theora_transcode_bufferin( ttc, frameiskey[0], vp3frame[0], framebytecount[0]);
/* if there's only one frame, it's the last in the stream */
if(state<2)
theora_transcode_packetout(ttc,1,&op);
else
theora_transcode_packetout(ttc,0,&op);
ogg_stream_packetin(to,&op);
{
signed char *temp=vp3frame[0];
vp3frame[0]=vp3frame[1];
vp3frame[1] = temp;
free(temp);
framebytecount[0]= framebytecount[1];
frameiskey[0] = frameiskey[1];
state--;
}
}
}
return videoflag;
}
/* returns, in seconds, absolute time of current packet in given
logical stream */
double transcode_granule_time(TC_INSTANCE *ttc,ogg_int64_t granulepos){
if(granulepos>=0){
ogg_int64_t iframe=granulepos>>ttc->keyframe_granule_shift;
ogg_int64_t pframe=granulepos-(iframe<<ttc->keyframe_granule_shift);
return (iframe+pframe)*
((double)ttc->fps_denominator/ttc->fps_numerator);
}
return(-1);
}
int main(int argc,char *argv[]){
int c,long_option_index,ret;
ogg_stream_state to; /* take physical pages, weld into a logical
stream of packets */
ogg_stream_state vo; /* take physical pages, weld into a logical
stream of packets */
ogg_page og; /* one Ogg bitstream page. Vorbis packets are inside */
ogg_packet op; /* one raw packet of data for decode */
theora_state td;
theora_info ti;
theora_comment tc;
vorbis_info vi; /* struct that stores all the static vorbis bitstream
settings */
vorbis_comment vc; /* struct that stores all the user comments */
vorbis_dsp_state vd; /* central working state for the packet->PCM decoder */
vorbis_block vb; /* local working space for packet->PCM decode */
int audioflag=0;
int videoflag=0;
int akbps=0;
int vkbps=0;
ogg_int64_t audio_bytesout=0;
ogg_int64_t video_bytesout=0;
double timebase;
FILE* outfile = stdout;
TC_INSTANCE ttc;
#ifdef _WIN32 /* We need to set stdin/stdout to binary mode. Damn windows. */
/* if we were reading/writing a file, it would also need to in
binary mode, eg, fopen("file.wav","wb"); */
/* Beware the evil ifdef. We avoid these where we can, but this one we
cannot. Don't add any more, you'll probably go to hell if you do. */
_setmode( _fileno( stdin ), _O_BINARY );
_setmode( _fileno( stdout ), _O_BINARY );
#endif
while((c=getopt_long(argc,argv,optstring,options,&long_option_index))!=EOF){
switch(c){
case 'o':
outfile=fopen(optarg,"wb");
if(outfile==NULL){
fprintf(stderr,"Unable to open output file '%s'\n", optarg);
exit(1);
}
break;;
case 'a':
audio_q=atof(optarg)*.099;
if(audio_q<-.1 || audio_q>1){
fprintf(stderr,"Illegal audio quality (choose -1 through 10)\n");
exit(1);
}
audio_r=-1;
break;
case 'v':
video_q=rint(atof(optarg)*6.3);
if(video_q<0 || video_q>63){
fprintf(stderr,"Illegal video quality (choose 0 through 10)\n");
exit(1);
}
video_r=0;
break;
case 'A':
audio_r=atof(optarg)*1000;
if(audio_q<0){
fprintf(stderr,"Illegal audio quality (choose > 0 please)\n");
exit(1);
}
audio_q=-99;
break;
case 'V':
video_r=rint(atof(optarg)*1000);
if(video_r<45000 || video_r>2000000){
fprintf(stderr,"Illegal video bitrate (choose 45kbps through 2000kbps)\n");
exit(1);
}
video_q=0;
break;
default:
usage();
}
}
while(optind<argc){
/* assume that anything following the options must be a filename */
id_file(argv[optind]);
optind++;
}
/* yayness. Set up Ogg output stream */
srand(time(NULL));
ogg_stream_init(&vo,rand());
ogg_stream_init(&to,rand()); /* oops, add one ot the above */
/* Set up Theora encoder */
if(!video){
fprintf(stderr,"No video files submitted for compression?\n");
exit(1);
}
/* Theora has a divisible-by-sixteen restriction for the encoded video size */
/* scale the frame size up to the nearest /16 and calculate offsets */
video_x=((frame_x + 15) >>4)<<4;
video_y=((frame_y + 15) >>4)<<4;
frame_x_offset=(video_x-frame_x)/2;
frame_y_offset=(video_y-frame_y)/2;
theora_info_init(&ti);
ti.width=video_x;
ti.height=video_y;
ti.frame_width=frame_x;
ti.frame_height=frame_y;
ti.offset_x=frame_x_offset;
ti.offset_y=frame_y_offset;
ti.fps_numerator=video_hzn;
ti.fps_denominator=video_hzd;
ti.aspect_numerator=video_an;
ti.aspect_denominator=video_ad;
ti.colorspace=OC_CS_UNSPECIFIED;
ti.target_bitrate=video_r;
ti.quality=video_q;
ti.dropframes_p=0;
ti.quick_p=1;
ti.keyframe_auto_p=1;
ti.keyframe_frequency=32768;
ti.keyframe_frequency_force=32768;
ti.keyframe_data_target_bitrate=video_r*1.5;
ti.keyframe_auto_threshold=80;
ti.keyframe_mindistance=8;
ti.noise_sensitivity=1;
theora_encode_init(&td,&ti);
theora_transcoder_init(&ti, &ttc);
theora_info_clear(&ti);
/* initialize Vorbis too, assuming we have audio to compress. */
if(audio){
vorbis_info_init(&vi);
if(audio_q>-99)
ret = vorbis_encode_init_vbr(&vi,audio_ch,audio_hz,audio_q);
else
ret = vorbis_encode_init(&vi,audio_ch,audio_hz,-1,audio_r,-1);
if(ret){
fprintf(stderr,"The Vorbis encoder could not set up a mode according to\n"
"the requested quality or bitrate.\n\n");
exit(1);
}
vorbis_comment_init(&vc);
vorbis_analysis_init(&vd,&vi);
vorbis_block_init(&vd,&vb);
}
/* write the bitstream header packets with proper page interleave */
/* first packet will get its own page automatically */
theora_encode_header(&td,&op);
ogg_stream_packetin(&to,&op);
if(ogg_stream_pageout(&to,&og)!=1){
fprintf(stderr,"Internal Ogg library error.\n");
exit(1);
}
fwrite(og.header,1,og.header_len,outfile);
fwrite(og.body,1,og.body_len,outfile);
/* create the remaining theora headers */
theora_comment_init(&tc);
theora_encode_comment(&tc,&op);
ogg_stream_packetin(&to,&op);
theora_encode_tables(&td,&op);
ogg_stream_packetin(&to,&op);
if(audio){
ogg_packet header;
ogg_packet header_comm;
ogg_packet header_code;
vorbis_analysis_headerout(&vd,&vc,&header,&header_comm,&header_code);
ogg_stream_packetin(&vo,&header); /* automatically placed in its own
page */
if(ogg_stream_pageout(&vo,&og)!=1){
fprintf(stderr,"Internal Ogg library error.\n");
exit(1);
}
fwrite(og.header,1,og.header_len,outfile);
fwrite(og.body,1,og.body_len,outfile);
/* remaining vorbis header packets */
ogg_stream_packetin(&vo,&header_comm);
ogg_stream_packetin(&vo,&header_code);
}
/* Flush the rest of our headers. This ensures
the actual data in each stream will start
on a new page, as per spec. */
while(1){
int result = ogg_stream_flush(&to,&og);
if(result<0){
/* can't get here */
fprintf(stderr,"Internal Ogg library error.\n");
exit(1);
}
if(result==0)break;
fwrite(og.header,1,og.header_len,outfile);
fwrite(og.body,1,og.body_len,outfile);
}
if(audio){
while(1){
int result=ogg_stream_flush(&vo,&og);
if(result<0){
/* can't get here */
fprintf(stderr,"Internal Ogg library error.\n");
exit(1);
}
if(result==0)break;
fwrite(og.header,1,og.header_len,outfile);
fwrite(og.body,1,og.body_len,outfile);
}
}
/* setup complete. Raw processing loop */
fprintf(stderr,"Compressing....\n");
while(1){
/* is there an audio page flushed? If not, fetch one if possible */
audioflag=fetch_and_process_audio(audio,&audiopage,&vo,&vd,&vb,audioflag);
/* is there a video page flushed? If not, fetch one if possible */
videoflag=fetch_and_process_video(video,&videopage,&to,&ttc,videoflag);
/* no pages of either? Must be end of stream. */
if(!audioflag && !videoflag)break;
/* which is earlier; the end of the audio page or the end of the
video page? Flush the earlier to stream */
{
int audio_or_video=-1;
double audiotime=
audioflag?vorbis_granule_time(&vd,ogg_page_granulepos(&audiopage)):-1;
double videotime=
videoflag?transcode_granule_time(&ttc,ogg_page_granulepos(&videopage)):-1;
if(!audioflag){
audio_or_video=1;
} else if(!videoflag) {
audio_or_video=0;
} else {
if(audiotime<videotime)
audio_or_video=0;
else
audio_or_video=1;
}
if(audio_or_video==1){
/* flush a video page */
video_bytesout+=fwrite(videopage.header,1,videopage.header_len,outfile);
video_bytesout+=fwrite(videopage.body,1,videopage.body_len,outfile);
videoflag=0;
timebase=videotime;
}else{
/* flush an audio page */
audio_bytesout+=fwrite(audiopage.header,1,audiopage.header_len,outfile);
audio_bytesout+=fwrite(audiopage.body,1,audiopage.body_len,outfile);
audioflag=0;
timebase=audiotime;
}
{
int hundredths=timebase*100-(long)timebase*100;
int seconds=(long)timebase%60;
int minutes=((long)timebase/60)%60;
int hours=(long)timebase/3600;
if(audio_or_video)
vkbps=rint(video_bytesout*8./timebase*.001);
else
akbps=rint(audio_bytesout*8./timebase*.001);
fprintf(stderr,
"\n %d:%02d:%02d.%02d audio: %dkbps video: %dkbps ",
hours,minutes,seconds,hundredths,akbps,vkbps);
}
}
}
/* clear out state */
if(audio){
ogg_stream_clear(&vo);
vorbis_block_clear(&vb);
vorbis_dsp_clear(&vd);
vorbis_comment_clear(&vc);
vorbis_info_clear(&vi);
}
if(video){
ogg_stream_clear(&to);
theora_clear(&td);
}
if(outfile && outfile!=stdout)fclose(outfile);
fprintf(stderr,"\r \ndone.\n\n");
return(0);
}
@@ -0,0 +1 @@
GetOpt routines ported from BSD-licensed sources, see comments.
@@ -0,0 +1,122 @@
/*
* Copyright (c) 1987, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)getopt.c 8.3 (Berkeley) 4/27/95";
#endif /* LIBC_SCCS and not lint
#include <sys/cdefs.h>
//__FBSDID("$FreeBSD: src/lib/libc/stdlib/getopt.c,v 1.6 2002/03/29 22:43:42 markm Exp $");
#include "namespace.h"*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/*#include "un-namespace.h"*/
/*#include "libc_private.h"*/
int opterr = 1, /* if error message should be printed */
optind = 1, /* index into parent argv vector */
optopt, /* character checked for validity */
optreset; /* reset getopt */
char *optarg; /* argument associated with option */
#define BADCH (int)'?'
#define BADARG (int)':'
#define EMSG ""
/*
* getopt --
* Parse argc/argv argument vector.
*/
int
getopt(nargc, nargv, ostr)
int nargc;
char * const *nargv;
const char *ostr;
{
static char *place = EMSG; /* option letter processing */
char *oli; /* option letter list index */
if (optreset || !*place) { /* update scanning pointer */
optreset = 0;
if (optind >= nargc || *(place = nargv[optind]) != '-') {
place = EMSG;
return (-1);
}
if (place[1] && *++place == '-') { /* found "--" */
++optind;
place = EMSG;
return (-1);
}
} /* option letter okay? */
if ((optopt = (int)*place++) == (int)':' ||
!(oli = strchr(ostr, optopt))) {
/*
* if the user didn't specify '-' as an option,
* assume it means -1.
*/
if (optopt == (int)'-')
return (-1);
if (!*place)
++optind;
if (opterr && *ostr != ':' && optopt != BADCH)
(void)fprintf(stderr, "%s: illegal option -- %c\n",
"progname", optopt);
return (BADCH);
}
if (*++oli != ':') { /* don't need argument */
optarg = NULL;
if (!*place)
++optind;
}
else { /* need an argument */
if (*place) /* no white space */
optarg = place;
else if (nargc <= ++optind) { /* no arg */
place = EMSG;
if (*ostr == ':')
return (BADARG);
if (opterr)
(void)fprintf(stderr,
"%s: option requires an argument -- %c\n",
"progname", optopt);
return (BADCH);
}
else /* white space */
optarg = nargv[optind];
place = EMSG;
++optind;
}
return (optopt); /* dump back option letter */
}
@@ -0,0 +1,110 @@
/* $NetBSD: getopt.h,v 1.4 2000/07/07 10:43:54 ad Exp $ */
/* $FreeBSD: src/include/getopt.h,v 1.1 2002/09/29 04:14:30 eric Exp $ */
/*-
* Copyright (c) 2000 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Dieter Baron and Thomas Klausner.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the NetBSD
* Foundation, Inc. and its contributors.
* 4. Neither the name of The NetBSD Foundation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _GETOPT_H_
#define _GETOPT_H_
#ifdef _WIN32
/* from <sys/cdefs.h> */
# ifdef __cplusplus
# define __BEGIN_DECLS extern "C" {
# define __END_DECLS }
# else
# define __BEGIN_DECLS
# define __END_DECLS
# endif
# define __P(args) args
#endif
/*#ifndef _WIN32
#include <sys/cdefs.h>
#include <unistd.h>
#endif*/
#ifdef _WIN32
# if !defined(GETOPT_API)
# define GETOPT_API __declspec(dllimport)
# endif
#endif
/*
* Gnu like getopt_long() and BSD4.4 getsubopt()/optreset extensions
*/
#if !defined(_POSIX_SOURCE) && !defined(_XOPEN_SOURCE)
#define no_argument 0
#define required_argument 1
#define optional_argument 2
struct option {
/* name of long option */
const char *name;
/*
* one of no_argument, required_argument, and optional_argument:
* whether option takes an argument
*/
int has_arg;
/* if not NULL, set *flag to val when option found */
int *flag;
/* if flag not NULL, value to set *flag to; else return value */
int val;
};
__BEGIN_DECLS
GETOPT_API int getopt_long __P((int, char * const *, const char *,
const struct option *, int *));
__END_DECLS
#endif
#ifdef _WIN32
/* These are global getopt variables */
__BEGIN_DECLS
GETOPT_API extern int opterr, /* if error message should be printed */
optind, /* index into parent argv vector */
optopt, /* character checked for validity */
optreset; /* reset getopt */
GETOPT_API extern char* optarg; /* argument associated with option */
/* Original getopt */
GETOPT_API int getopt __P((int, char * const *, const char *));
__END_DECLS
#endif
#endif /* !_GETOPT_H_ */
@@ -0,0 +1,547 @@
/* $NetBSD: getopt_long.c,v 1.15 2002/01/31 22:43:40 tv Exp $ */
/* $FreeBSD: src/lib/libc/stdlib/getopt_long.c,v 1.2 2002/10/16 22:18:42 alfred Exp $ */
/*-
* Copyright (c) 2000 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Dieter Baron and Thomas Klausner.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the NetBSD
* Foundation, Inc. and its contributors.
* 4. Neither the name of The NetBSD Foundation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <getopt.h>
#include <stdlib.h>
#include <string.h>
#ifdef _WIN32
/* Windows needs warnx(). We change the definition though:
* 1. (another) global is defined, opterrmsg, which holds the error message
* 2. errors are always printed out on stderr w/o the program name
* Note that opterrmsg always gets set no matter what opterr is set to. The
* error message will not be printed if opterr is 0 as usual.
*/
#include <stdio.h>
#include <stdarg.h>
GETOPT_API extern char opterrmsg[128];
char opterrmsg[128]; /* last error message is stored here */
static void warnx(int print_error, const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
if (fmt != NULL)
_vsnprintf(opterrmsg, 128, fmt, ap);
else
opterrmsg[0]='\0';
va_end(ap);
if (print_error) {
fprintf(stderr, opterrmsg);
fprintf(stderr, "\n");
}
}
#endif /*_WIN32*/
/* not part of the original file */
#ifndef _DIAGASSERT
#define _DIAGASSERT(X)
#endif
#if HAVE_CONFIG_H && !HAVE_GETOPT_LONG && !HAVE_DECL_OPTIND
#define REPLACE_GETOPT
#endif
#ifdef REPLACE_GETOPT
#ifdef __weak_alias
__weak_alias(getopt,_getopt)
#endif
int opterr = 1; /* if error message should be printed */
int optind = 1; /* index into parent argv vector */
int optopt = '?'; /* character checked for validity */
int optreset; /* reset getopt */
char *optarg; /* argument associated with option */
#elif HAVE_CONFIG_H && !HAVE_DECL_OPTRESET
static int optreset;
#endif
#ifdef __weak_alias
__weak_alias(getopt_long,_getopt_long)
#endif
#if !HAVE_GETOPT_LONG
#define IGNORE_FIRST (*options == '-' || *options == '+')
#define PRINT_ERROR ((opterr) && ((*options != ':') \
|| (IGNORE_FIRST && options[1] != ':')))
#define IS_POSIXLY_CORRECT (getenv("POSIXLY_CORRECT") != NULL)
#define PERMUTE (!IS_POSIXLY_CORRECT && !IGNORE_FIRST)
/* XXX: GNU ignores PC if *options == '-' */
#define IN_ORDER (!IS_POSIXLY_CORRECT && *options == '-')
/* return values */
#define BADCH (int)'?'
#define BADARG ((IGNORE_FIRST && options[1] == ':') \
|| (*options == ':') ? (int)':' : (int)'?')
#define INORDER (int)1
#define EMSG ""
static int getopt_internal(int, char * const *, const char *);
static int gcd(int, int);
static void permute_args(int, int, int, char * const *);
static char *place = EMSG; /* option letter processing */
/* XXX: set optreset to 1 rather than these two */
static int nonopt_start = -1; /* first non option argument (for permute) */
static int nonopt_end = -1; /* first option after non options (for permute) */
/* Error messages */
static const char recargchar[] = "option requires an argument -- %c";
static const char recargstring[] = "option requires an argument -- %s";
static const char ambig[] = "ambiguous option -- %.*s";
static const char noarg[] = "option doesn't take an argument -- %.*s";
static const char illoptchar[] = "unknown option -- %c";
static const char illoptstring[] = "unknown option -- %s";
/*
* Compute the greatest common divisor of a and b.
*/
static int
gcd(a, b)
int a;
int b;
{
int c;
c = a % b;
while (c != 0) {
a = b;
b = c;
c = a % b;
}
return b;
}
/*
* Exchange the block from nonopt_start to nonopt_end with the block
* from nonopt_end to opt_end (keeping the same order of arguments
* in each block).
*/
static void
permute_args(panonopt_start, panonopt_end, opt_end, nargv)
int panonopt_start;
int panonopt_end;
int opt_end;
char * const *nargv;
{
int cstart, cyclelen, i, j, ncycle, nnonopts, nopts, pos;
char *swap;
_DIAGASSERT(nargv != NULL);
/*
* compute lengths of blocks and number and size of cycles
*/
nnonopts = panonopt_end - panonopt_start;
nopts = opt_end - panonopt_end;
ncycle = gcd(nnonopts, nopts);
cyclelen = (opt_end - panonopt_start) / ncycle;
for (i = 0; i < ncycle; i++) {
cstart = panonopt_end+i;
pos = cstart;
for (j = 0; j < cyclelen; j++) {
if (pos >= panonopt_end)
pos -= nnonopts;
else
pos += nopts;
swap = nargv[pos];
/* LINTED const cast */
((char **) nargv)[pos] = nargv[cstart];
/* LINTED const cast */
((char **)nargv)[cstart] = swap;
}
}
}
/*
* getopt_internal --
* Parse argc/argv argument vector. Called by user level routines.
* Returns -2 if -- is found (can be long option or end of options marker).
*/
static int
getopt_internal(nargc, nargv, options)
int nargc;
char * const *nargv;
const char *options;
{
char *oli; /* option letter list index */
int optchar;
_DIAGASSERT(nargv != NULL);
_DIAGASSERT(options != NULL);
optarg = NULL;
/*
* XXX Some programs (like rsyncd) expect to be able to
* XXX re-initialize optind to 0 and have getopt_long(3)
* XXX properly function again. Work around this braindamage.
*/
if (optind == 0)
optind = 1;
if (optreset)
nonopt_start = nonopt_end = -1;
start:
if (optreset || !*place) { /* update scanning pointer */
optreset = 0;
if (optind >= nargc) { /* end of argument vector */
place = EMSG;
if (nonopt_end != -1) {
/* do permutation, if we have to */
permute_args(nonopt_start, nonopt_end,
optind, nargv);
optind -= nonopt_end - nonopt_start;
}
else if (nonopt_start != -1) {
/*
* If we skipped non-options, set optind
* to the first of them.
*/
optind = nonopt_start;
}
nonopt_start = nonopt_end = -1;
return -1;
}
if ((*(place = nargv[optind]) != '-')
|| (place[1] == '\0')) { /* found non-option */
place = EMSG;
if (IN_ORDER) {
/*
* GNU extension:
* return non-option as argument to option 1
*/
optarg = nargv[optind++];
return INORDER;
}
if (!PERMUTE) {
/*
* if no permutation wanted, stop parsing
* at first non-option
*/
return -1;
}
/* do permutation */
if (nonopt_start == -1)
nonopt_start = optind;
else if (nonopt_end != -1) {
permute_args(nonopt_start, nonopt_end,
optind, nargv);
nonopt_start = optind -
(nonopt_end - nonopt_start);
nonopt_end = -1;
}
optind++;
/* process next argument */
goto start;
}
if (nonopt_start != -1 && nonopt_end == -1)
nonopt_end = optind;
if (place[1] && *++place == '-') { /* found "--" */
place++;
return -2;
}
}
if ((optchar = (int)*place++) == (int)':' ||
(oli = strchr(options + (IGNORE_FIRST ? 1 : 0), optchar)) == NULL) {
/* option letter unknown or ':' */
if (!*place)
++optind;
#ifndef _WIN32
if (PRINT_ERROR)
warnx(illoptchar, optchar);
#else
warnx(PRINT_ERROR, illoptchar, optchar);
#endif
optopt = optchar;
return BADCH;
}
if (optchar == 'W' && oli[1] == ';') { /* -W long-option */
/* XXX: what if no long options provided (called by getopt)? */
if (*place)
return -2;
if (++optind >= nargc) { /* no arg */
place = EMSG;
#ifndef _WIN32
if (PRINT_ERROR)
warnx(recargchar, optchar);
#else
warnx(PRINT_ERROR, recargchar, optchar);
#endif
optopt = optchar;
return BADARG;
} else /* white space */
place = nargv[optind];
/*
* Handle -W arg the same as --arg (which causes getopt to
* stop parsing).
*/
return -2;
}
if (*++oli != ':') { /* doesn't take argument */
if (!*place)
++optind;
} else { /* takes (optional) argument */
optarg = NULL;
if (*place) /* no white space */
optarg = place;
/* XXX: disable test for :: if PC? (GNU doesn't) */
else if (oli[1] != ':') { /* arg not optional */
if (++optind >= nargc) { /* no arg */
place = EMSG;
#ifndef _WIN32
if (PRINT_ERROR)
warnx(recargchar, optchar);
#else
warnx(PRINT_ERROR, recargchar, optchar);
#endif
optopt = optchar;
return BADARG;
} else
optarg = nargv[optind];
}
place = EMSG;
++optind;
}
/* dump back option letter */
return optchar;
}
#ifdef REPLACE_GETOPT
/*
* getopt --
* Parse argc/argv argument vector.
*
* [eventually this will replace the real getopt]
*/
int
getopt(nargc, nargv, options)
int nargc;
char * const *nargv;
const char *options;
{
int retval;
_DIAGASSERT(nargv != NULL);
_DIAGASSERT(options != NULL);
if ((retval = getopt_internal(nargc, nargv, options)) == -2) {
++optind;
/*
* We found an option (--), so if we skipped non-options,
* we have to permute.
*/
if (nonopt_end != -1) {
permute_args(nonopt_start, nonopt_end, optind,
nargv);
optind -= nonopt_end - nonopt_start;
}
nonopt_start = nonopt_end = -1;
retval = -1;
}
return retval;
}
#endif
/*
* getopt_long --
* Parse argc/argv argument vector.
*/
int
getopt_long(nargc, nargv, options, long_options, idx)
int nargc;
char * const *nargv;
const char *options;
const struct option *long_options;
int *idx;
{
int retval;
_DIAGASSERT(nargv != NULL);
_DIAGASSERT(options != NULL);
_DIAGASSERT(long_options != NULL);
/* idx may be NULL */
if ((retval = getopt_internal(nargc, nargv, options)) == -2) {
char *current_argv, *has_equal;
size_t current_argv_len;
int i, match;
current_argv = place;
match = -1;
optind++;
place = EMSG;
if (*current_argv == '\0') { /* found "--" */
/*
* We found an option (--), so if we skipped
* non-options, we have to permute.
*/
if (nonopt_end != -1) {
permute_args(nonopt_start, nonopt_end,
optind, nargv);
optind -= nonopt_end - nonopt_start;
}
nonopt_start = nonopt_end = -1;
return -1;
}
if ((has_equal = strchr(current_argv, '=')) != NULL) {
/* argument found (--option=arg) */
current_argv_len = has_equal - current_argv;
has_equal++;
} else
current_argv_len = strlen(current_argv);
for (i = 0; long_options[i].name; i++) {
/* find matching long option */
if (strncmp(current_argv, long_options[i].name,
current_argv_len))
continue;
if (strlen(long_options[i].name) ==
(unsigned)current_argv_len) {
/* exact match */
match = i;
break;
}
if (match == -1) /* partial match */
match = i;
else {
/* ambiguous abbreviation */
#ifndef _WIN32
if (PRINT_ERROR)
warnx(ambig, (int)current_argv_len,
current_argv);
#else
warnx(PRINT_ERROR, ambig, (int)current_argv_len,
current_argv);
#endif
optopt = 0;
return BADCH;
}
}
if (match != -1) { /* option found */
if (long_options[match].has_arg == no_argument
&& has_equal) {
#ifndef _WIN32
if (PRINT_ERROR)
warnx(noarg, (int)current_argv_len,
current_argv);
#else
warnx(PRINT_ERROR, noarg, (int)current_argv_len,
current_argv);
#endif
/*
* XXX: GNU sets optopt to val regardless of
* flag
*/
if (long_options[match].flag == NULL)
optopt = long_options[match].val;
else
optopt = 0;
return BADARG;
}
if (long_options[match].has_arg == required_argument ||
long_options[match].has_arg == optional_argument) {
if (has_equal)
optarg = has_equal;
else if (long_options[match].has_arg ==
required_argument) {
/*
* optional argument doesn't use
* next nargv
*/
optarg = nargv[optind++];
}
}
if ((long_options[match].has_arg == required_argument)
&& (optarg == NULL)) {
/*
* Missing argument; leading ':'
* indicates no error should be generated
*/
#ifndef _WIN32
if (PRINT_ERROR)
warnx(recargstring, current_argv);
#else
warnx(PRINT_ERROR, recargstring, current_argv);
#endif
/*
* XXX: GNU sets optopt to val regardless
* of flag
*/
if (long_options[match].flag == NULL)
optopt = long_options[match].val;
else
optopt = 0;
--optind;
return BADARG;
}
} else { /* unknown option */
#ifndef _WIN32
if (PRINT_ERROR)
warnx(illoptstring, current_argv);
#else
warnx(PRINT_ERROR, illoptstring, current_argv);
#endif
optopt = 0;
return BADCH;
}
if (long_options[match].flag) {
*long_options[match].flag = long_options[match].val;
retval = 0;
} else
retval = long_options[match].val;
if (idx)
*idx = match;
}
return retval;
}
#endif /* !GETOPT_LONG */