Force consistent line endings.

I'd suggest enabling the EolExtension:
this way we won't go back and forth here.
This commit is contained in:
Jason Felds
2011-03-16 15:51:54 -04:00
parent e27b454306
commit 7c4044a2fc
75 changed files with 24426 additions and 24404 deletions
+764 -764
View File
File diff suppressed because it is too large Load Diff
+63 -63
View File
@@ -1,63 +1,63 @@
#ifndef NOTES_LOADER_SMA_H
#define NOTES_LOADER_SMA_H
#include "GameConstantsAndTypes.h"
#include "BackgroundUtil.h"
class MsdFile;
class Song;
class Steps;
class TimingData;
/** @brief Reads a Song from a .SMA file. */
namespace SMALoader
{
void LoadFromSMATokens( RString sStepsType,
RString sDescription,
RString sDifficulty,
RString sMeter,
RString sRadarValues,
RString sNoteData,
Steps &out );
bool LoadFromDir( const RString &sPath, Song &out );
void TidyUpData( Song &song, bool bFromCache );
bool LoadFromSMAFile( const RString &sPath, Song &out );
void GetApplicableFiles( const RString &sPath, vector<RString> &out );
bool LoadTimingFromFile( const RString &fn, TimingData &out );
void LoadTimingFromSMAFile( const MsdFile &msd, TimingData &out );
bool LoadEditFromFile( RString sEditFilePath, ProfileSlot slot, bool bAddStepsToSong );
bool LoadEditFromBuffer( const RString &sBuffer, const RString &sEditFilePath, ProfileSlot slot );
bool LoadEditFromMsd( const MsdFile &msd, const RString &sEditFilePath, ProfileSlot slot, bool bAddStepsToSong );
bool LoadFromBGChangesString( BackgroundChange &change, const RString &sBGChangeExpression );
};
#endif
/**
* @file
* @author Aldo Fregoso, Jason Felds (c) 2009-2011
* @section LICENSE
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, and/or sell copies of the Software, and to permit persons to
* whom the Software is furnished to do so, provided that the above
* copyright notice(s) and this permission notice appear in all copies of
* the Software and that both the above copyright notice(s) and this
* permission notice appear in supporting documentation.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef NOTES_LOADER_SMA_H
#define NOTES_LOADER_SMA_H
#include "GameConstantsAndTypes.h"
#include "BackgroundUtil.h"
class MsdFile;
class Song;
class Steps;
class TimingData;
/** @brief Reads a Song from a .SMA file. */
namespace SMALoader
{
void LoadFromSMATokens( RString sStepsType,
RString sDescription,
RString sDifficulty,
RString sMeter,
RString sRadarValues,
RString sNoteData,
Steps &out );
bool LoadFromDir( const RString &sPath, Song &out );
void TidyUpData( Song &song, bool bFromCache );
bool LoadFromSMAFile( const RString &sPath, Song &out );
void GetApplicableFiles( const RString &sPath, vector<RString> &out );
bool LoadTimingFromFile( const RString &fn, TimingData &out );
void LoadTimingFromSMAFile( const MsdFile &msd, TimingData &out );
bool LoadEditFromFile( RString sEditFilePath, ProfileSlot slot, bool bAddStepsToSong );
bool LoadEditFromBuffer( const RString &sBuffer, const RString &sEditFilePath, ProfileSlot slot );
bool LoadEditFromMsd( const MsdFile &msd, const RString &sEditFilePath, ProfileSlot slot, bool bAddStepsToSong );
bool LoadFromBGChangesString( BackgroundChange &change, const RString &sBGChangeExpression );
};
#endif
/**
* @file
* @author Aldo Fregoso, Jason Felds (c) 2009-2011
* @section LICENSE
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, and/or sell copies of the Software, and to permit persons to
* whom the Software is furnished to do so, provided that the above
* copyright notice(s) and this permission notice appear in all copies of
* the Software and that both the above copyright notice(s) and this
* permission notice appear in supporting documentation.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
+1260 -1260
View File
File diff suppressed because it is too large Load Diff
+103 -103
View File
@@ -1,103 +1,103 @@
/** @brief SSCLoader - Reads a Song and its Steps from a .SSC file. */
#ifndef NotesLoaderSSC_H
#define NotesLoaderSSC_H
#include "GameConstantsAndTypes.h"
class MsdFile;
class Song;
class Steps;
class TimingData;
/**
* @brief The various states while parsing a .ssc file.
*/
enum SSCLoadingStates
{
GETTING_SONG_INFO, /**< Retrieving song information. */
GETTING_STEP_INFO, /**< Retrieving step information. */
GETTING_STEP_TIMING_INFO, /**< Retrieving a step's individual timing information. */
GETTING_NOTE_INFO, /**< Retrieving the specific notes. This state may be deprecated. */
NUM_SSCLoadingStates /**< The number of states used. */
};
const float VERSION_RADAR_FAKE = 0.53f;
/**
* @brief The SSCLoader handles all of the parsing needed for .ssc files.
*/
namespace SSCLoader
{
/**
* @brief Attempt to load a song from a specified path.
* @param sPath a const reference to the path on the hard drive to check.
* @param out a reference to the Song that will retrieve the song information.
* @return its success or failure.
*/
bool LoadFromDir( const RString &sPath, Song &out );
/**
* @brief Attempt to load the specified ssc file.
* @param sPath a const reference to the path on the hard drive to check.
* @param out a reference to the Song that will retrieve the song information.
* @param bFromCache a check to see if we are getting certain information from the cache file.
* @return its success or failure.
*/
bool LoadFromSSCFile( const RString &sPath, Song &out, bool bFromCache = false );
/**
* @brief Retrieve the list of .ssc files.
* @param sPath a const reference to the path on the hard drive to check.
* @param out a vector of files found in the path.
*/
void GetApplicableFiles( const RString &sPath, vector<RString> &out );
/**
* @brief Attempt to load an edit from the hard drive.
* @param sEditFilePath a path on the hard drive to check.
* @param slot the Profile of the user with the edit.
* @param bAddStepsToSong a flag to determine if we add the edit steps to the song file.
* @return its success or failure.
*/
bool LoadEditFromFile( RString sEditFilePath, ProfileSlot slot, bool bAddStepsToSong );
/**
* @brief Attempt to parse the edit file in question.
* @param msd the edit file itself.
* @param sEditFilePath a const reference to a path on the hard drive to check.
* @param slot the Profile of the user with the edit.
* @param bAddStepsToSong a flag to determine if we add the edit steps to the song file.
* @return its success or failure.
*/
bool LoadEditFromMsd( const MsdFile &msd, const RString &sEditFilePath, ProfileSlot slot, bool bAddStepsToSong );
/**
* @brief Perform some cleanup on the loaded song.
* @param song a reference to the song that may need cleaning up.
* @param bFromCache a flag to determine if this song is loaded from a cache file.
*/
void TidyUpData( Song &song, bool bFromCache );
}
#endif
/**
* @file
* @author Jason Felds (c) 2011
*
* @section LICENSE
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, and/or sell copies of the Software, and to permit persons to
* whom the Software is furnished to do so, provided that the above
* copyright notice(s) and this permission notice appear in all copies of
* the Software and that both the above copyright notice(s) and this
* permission notice appear in supporting documentation.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
/** @brief SSCLoader - Reads a Song and its Steps from a .SSC file. */
#ifndef NotesLoaderSSC_H
#define NotesLoaderSSC_H
#include "GameConstantsAndTypes.h"
class MsdFile;
class Song;
class Steps;
class TimingData;
/**
* @brief The various states while parsing a .ssc file.
*/
enum SSCLoadingStates
{
GETTING_SONG_INFO, /**< Retrieving song information. */
GETTING_STEP_INFO, /**< Retrieving step information. */
GETTING_STEP_TIMING_INFO, /**< Retrieving a step's individual timing information. */
GETTING_NOTE_INFO, /**< Retrieving the specific notes. This state may be deprecated. */
NUM_SSCLoadingStates /**< The number of states used. */
};
const float VERSION_RADAR_FAKE = 0.53f;
/**
* @brief The SSCLoader handles all of the parsing needed for .ssc files.
*/
namespace SSCLoader
{
/**
* @brief Attempt to load a song from a specified path.
* @param sPath a const reference to the path on the hard drive to check.
* @param out a reference to the Song that will retrieve the song information.
* @return its success or failure.
*/
bool LoadFromDir( const RString &sPath, Song &out );
/**
* @brief Attempt to load the specified ssc file.
* @param sPath a const reference to the path on the hard drive to check.
* @param out a reference to the Song that will retrieve the song information.
* @param bFromCache a check to see if we are getting certain information from the cache file.
* @return its success or failure.
*/
bool LoadFromSSCFile( const RString &sPath, Song &out, bool bFromCache = false );
/**
* @brief Retrieve the list of .ssc files.
* @param sPath a const reference to the path on the hard drive to check.
* @param out a vector of files found in the path.
*/
void GetApplicableFiles( const RString &sPath, vector<RString> &out );
/**
* @brief Attempt to load an edit from the hard drive.
* @param sEditFilePath a path on the hard drive to check.
* @param slot the Profile of the user with the edit.
* @param bAddStepsToSong a flag to determine if we add the edit steps to the song file.
* @return its success or failure.
*/
bool LoadEditFromFile( RString sEditFilePath, ProfileSlot slot, bool bAddStepsToSong );
/**
* @brief Attempt to parse the edit file in question.
* @param msd the edit file itself.
* @param sEditFilePath a const reference to a path on the hard drive to check.
* @param slot the Profile of the user with the edit.
* @param bAddStepsToSong a flag to determine if we add the edit steps to the song file.
* @return its success or failure.
*/
bool LoadEditFromMsd( const MsdFile &msd, const RString &sEditFilePath, ProfileSlot slot, bool bAddStepsToSong );
/**
* @brief Perform some cleanup on the loaded song.
* @param song a reference to the song that may need cleaning up.
* @param bFromCache a flag to determine if this song is loaded from a cache file.
*/
void TidyUpData( Song &song, bool bFromCache );
}
#endif
/**
* @file
* @author Jason Felds (c) 2011
*
* @section LICENSE
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, and/or sell copies of the Software, and to permit persons to
* whom the Software is furnished to do so, provided that the above
* copyright notice(s) and this permission notice appear in all copies of
* the Software and that both the above copyright notice(s) and this
* permission notice appear in supporting documentation.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
+46 -46
View File
@@ -1,46 +1,46 @@
#ifndef RAGE_FILE_MANAGER_READAHEAD_H
#define RAGE_FILE_MANAGER_READAHEAD_H
#include "RageFileBasic.h"
/** @brief Utilities for reading the RageFiles. */
namespace RageFileManagerReadAhead
{
void Init();
void Shutdown();
// Nonblockingly read ahead iBytes in pFile, starting at the current file position.
void ReadAhead( RageFileBasic *pFile, int iBytes );
/* Discard iBytes of kernel cache, starting at the current file position plus
* iRelativePosition (which may be negative). */
void DiscardCache( RageFileBasic *pFile, int iRelativePosition, int iBytes );
void CacheHintStreaming( RageFileBasic *pFile );
};
#endif
/*
* Copyright (c) 2010 Glenn Maynard
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, and/or sell copies of the Software, and to permit persons to
* whom the Software is furnished to do so, provided that the above
* copyright notice(s) and this permission notice appear in all copies of
* the Software and that both the above copyright notice(s) and this
* permission notice appear in supporting documentation.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef RAGE_FILE_MANAGER_READAHEAD_H
#define RAGE_FILE_MANAGER_READAHEAD_H
#include "RageFileBasic.h"
/** @brief Utilities for reading the RageFiles. */
namespace RageFileManagerReadAhead
{
void Init();
void Shutdown();
// Nonblockingly read ahead iBytes in pFile, starting at the current file position.
void ReadAhead( RageFileBasic *pFile, int iBytes );
/* Discard iBytes of kernel cache, starting at the current file position plus
* iRelativePosition (which may be negative). */
void DiscardCache( RageFileBasic *pFile, int iRelativePosition, int iBytes );
void CacheHintStreaming( RageFileBasic *pFile );
};
#endif
/*
* Copyright (c) 2010 Glenn Maynard
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, and/or sell copies of the Software, and to permit persons to
* whom the Software is furnished to do so, provided that the above
* copyright notice(s) and this permission notice appear in all copies of
* the Software and that both the above copyright notice(s) and this
* permission notice appear in supporting documentation.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
+318 -318
View File
@@ -1,318 +1,318 @@
#include "global.h"
#include "RageSurface_Load_PNG.h"
#include "RageUtil.h"
#include "RageLog.h"
#include "RageFile.h"
#include "RageSurface.h"
#if defined(_WINDOWS) || defined(_XBOX)
# include "libpng/include/png.h"
# if defined(_MSC_VER)
# if defined(_XBOX)
# pragma comment(lib, "libpng/lib/xboxlibpng.lib")
# else
# pragma comment(lib, "libpng/lib/libpng.lib")
# endif
# pragma warning(disable: 4611) /* interaction between '_setjmp' and C++ object destruction is non-portable */
# endif // _MSC_VER
#else
# include <png.h>
#endif
#if defined(_XBOX)
# include <malloc.h> // for alloca
# include "archutils/Xbox/VirtualMemory.h"
#endif
namespace
{
void RageFile_png_read( png_struct *png, png_byte *p, png_size_t size )
{
CHECKPOINT;
RageFile *f = (RageFile *) png_get_io_ptr(png);
int got = f->Read( p, size );
if( got == -1 )
{
/* png_error will call PNG_Error, which will longjmp. If we just pass
* GetError().c_str() to it, a temporary may be created; since control
* never returns here, it may never be destructed and we could leak. */
static char error[256];
strncpy( error, f->GetError(), sizeof(error) );
error[sizeof(error)-1] = 0;
png_error( png, error );
}
else if( got != (int) size )
png_error( png, "Unexpected EOF" );
}
struct error_info
{
char *err;
const char *fn;
};
void PNG_Error( png_struct *png, const char *error )
{
CHECKPOINT;
error_info *info = (error_info *) png_get_error_ptr(png);
strncpy( info->err, error, 1024 );
info->err[1023] = 0;
LOG->Trace( "loading \"%s\": err: %s", info->fn, info->err );
longjmp( png_jmpbuf(png), 1 );
}
void PNG_Warning( png_struct *png, const char *warning )
{
CHECKPOINT;
error_info *info = (error_info *) png_get_io_ptr(png);
LOG->Trace( "loading \"%s\": warning: %s", info->fn, warning );
}
/* Since libpng forces us to use longjmp (gross!), this function shouldn't create any C++
* objects, and needs to watch out for memleaks. */
static RageSurface *RageSurface_Load_PNG( RageFile *f, const char *fn, char errorbuf[1024], bool bHeaderOnly )
{
error_info error;
error.err = errorbuf;
error.fn = fn;
png_struct *png = png_create_read_struct( PNG_LIBPNG_VER_STRING, &error, PNG_Error, PNG_Warning );
#if defined(XBOX)
while(png == NULL)
{
if(!vmem_Manager.DecommitLRU())
break;
png = png_create_read_struct( PNG_LIBPNG_VER_STRING, &error, PNG_Error, PNG_Warning );
}
#endif
if( png == NULL )
{
sprintf( errorbuf, "creating png_create_read_struct failed");
return NULL;
}
png_info *info_ptr = png_create_info_struct(png);
if( info_ptr == NULL )
{
png_destroy_read_struct( &png, NULL, NULL );
sprintf( errorbuf, "creating png_create_info_struct failed");
return NULL;
}
RageSurface *volatile img = NULL;
CHECKPOINT;
if( setjmp(png_jmpbuf(png) ))
{
png_destroy_read_struct( &png, &info_ptr, NULL );
delete img;
return NULL;
}
CHECKPOINT;
png_set_read_fn( png, f, RageFile_png_read );
png_read_info( png, info_ptr );
png_uint_32 width, height;
int bit_depth, color_type;
png_get_IHDR( png, info_ptr, &width, &height, &bit_depth, &color_type, NULL, NULL, NULL );
/* If bHeaderOnly is true, don't allocate the pixel storage space or decompress
* the image. Just return an empty surface with only the width and height set. */
if( bHeaderOnly )
{
CHECKPOINT;
img = CreateSurfaceFrom( width, height, 32, 0, 0, 0, 0, NULL, width*4 );
png_destroy_read_struct( &png, &info_ptr, NULL );
return img;
}
CHECKPOINT;
png_set_strip_16(png); /* 16bit->8bit */
png_set_packing( png ); /* 1,2,4 bit->8 bit */
/* Expand grayscale images to the full 8 bits from 1, 2, or 4 bits/pixel */
if( color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8 )
png_set_expand_gray_1_2_4_to_8( png );
/* These are set for type == PALETTE. */
RageSurfaceColor colors[256];
int iColorKey = -1;
/* We import three types of files: paletted, RGBX and RGBA. The only difference
* between RGBX and RGBA is that RGBX won't set the alpha mask, so it's easier
* to tell later on that there's no alpha (without actually having to do a pixel scan). */
enum { PALETTE, RGBX, RGBA } type;
switch( color_type )
{
case PNG_COLOR_TYPE_GRAY:
/* Fake PNG_COLOR_TYPE_GRAY. */
for( int i = 0; i < 256; ++i )
{
colors[i].r = colors[i].g = colors[i].b = (int8_t) i;
colors[i].a = 0xFF;
}
type = PALETTE;
break;
case PNG_COLOR_TYPE_GRAY_ALPHA:
type = RGBA;
png_set_gray_to_rgb( png );
break;
case PNG_COLOR_TYPE_PALETTE:
type = PALETTE;
break;
case PNG_COLOR_TYPE_RGB:
type = RGBX;
break;
case PNG_COLOR_TYPE_RGB_ALPHA:
type = RGBA;
break;
default:
FAIL_M(ssprintf( "%i", color_type) );
}
CHECKPOINT;
if( color_type == PNG_COLOR_TYPE_GRAY )
{
png_color_16 *trans;
if( png_get_tRNS( png, info_ptr, NULL, NULL, &trans ) == PNG_INFO_tRNS )
iColorKey = trans->gray;
}
else if( color_type == PNG_COLOR_TYPE_PALETTE )
{
int num_palette;
png_color *palette;
int ret = png_get_PLTE( png, info_ptr, &palette, &num_palette );
ASSERT( ret == PNG_INFO_PLTE );
png_byte *trans = NULL;
int num_trans = 0;
png_get_tRNS( png, info_ptr, &trans, &num_trans, NULL );
for( int i = 0; i < num_palette; ++i )
{
colors[i].r = palette[i].red;
colors[i].g = palette[i].green;
colors[i].b = palette[i].blue;
colors[i].a = 0xFF;
if( i < num_trans )
colors[i].a = trans[i];
}
}
else
{
/* If we have RGB image and tRNS, it's a color key. Just convert it to RGBA. */
if( png_get_valid(png, info_ptr, PNG_INFO_tRNS) )
{
/* We don't care about RGB color keys; just convert them to alpha. */
png_set_tRNS_to_alpha( png );
type = RGBA;
}
/* RGB->RGBX */
png_set_filler( png, 0xff, PNG_FILLER_AFTER );
}
png_set_interlace_handling( png );
CHECKPOINT;
png_read_update_info( png, info_ptr );
switch( type )
{
case PALETTE:
img = CreateSurface( width, height, 8, 0, 0, 0, 0 );
memcpy( img->fmt.palette->colors, colors, 256*sizeof(RageSurfaceColor) );
if( iColorKey != -1 )
img->format->palette->colors[ iColorKey ].a = 0;
break;
case RGBX:
case RGBA:
img = CreateSurface( width, height, 32,
Swap32BE( 0xFF000000 ),
Swap32BE( 0x00FF0000 ),
Swap32BE( 0x0000FF00 ),
Swap32BE( type == RGBA? 0x000000FF:0x00000000 ) );
break;
default:
FAIL_M(ssprintf( "%i", type) );
}
ASSERT( img );
/* alloca to prevent memleaks if libpng longjmps us */
png_byte **row_pointers = (png_byte **) alloca( sizeof(png_byte*) * height );
CHECKPOINT_M( ssprintf("%p",row_pointers) );
for( unsigned y = 0; y < height; ++y )
{
png_byte *p = (png_byte *) img->pixels;
row_pointers[y] = p + img->pitch*y;
}
CHECKPOINT;
png_read_image( png, row_pointers );
CHECKPOINT;
png_read_end( png, info_ptr );
png_destroy_read_struct( &png, &info_ptr, NULL );
return img;
}
};
RageSurfaceUtils::OpenResult RageSurface_Load_PNG( const RString &sPath, RageSurface *&ret, bool bHeaderOnly, RString &error )
{
RageFile f;
if( !f.Open( sPath ) )
{
error = f.GetError();
return RageSurfaceUtils::OPEN_FATAL_ERROR;
}
char errorbuf[1024];
ret = RageSurface_Load_PNG( &f, sPath, errorbuf, bHeaderOnly );
if( ret == NULL )
{
error = errorbuf;
return RageSurfaceUtils::OPEN_UNKNOWN_FILE_FORMAT; // XXX
}
return RageSurfaceUtils::OPEN_OK;
}
/*
* (c) 2004 Glenn Maynard
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, and/or sell copies of the Software, and to permit persons to
* whom the Software is furnished to do so, provided that the above
* copyright notice(s) and this permission notice appear in all copies of
* the Software and that both the above copyright notice(s) and this
* permission notice appear in supporting documentation.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
#include "global.h"
#include "RageSurface_Load_PNG.h"
#include "RageUtil.h"
#include "RageLog.h"
#include "RageFile.h"
#include "RageSurface.h"
#if defined(_WINDOWS) || defined(_XBOX)
# include "libpng/include/png.h"
# if defined(_MSC_VER)
# if defined(_XBOX)
# pragma comment(lib, "libpng/lib/xboxlibpng.lib")
# else
# pragma comment(lib, "libpng/lib/libpng.lib")
# endif
# pragma warning(disable: 4611) /* interaction between '_setjmp' and C++ object destruction is non-portable */
# endif // _MSC_VER
#else
# include <png.h>
#endif
#if defined(_XBOX)
# include <malloc.h> // for alloca
# include "archutils/Xbox/VirtualMemory.h"
#endif
namespace
{
void RageFile_png_read( png_struct *png, png_byte *p, png_size_t size )
{
CHECKPOINT;
RageFile *f = (RageFile *) png_get_io_ptr(png);
int got = f->Read( p, size );
if( got == -1 )
{
/* png_error will call PNG_Error, which will longjmp. If we just pass
* GetError().c_str() to it, a temporary may be created; since control
* never returns here, it may never be destructed and we could leak. */
static char error[256];
strncpy( error, f->GetError(), sizeof(error) );
error[sizeof(error)-1] = 0;
png_error( png, error );
}
else if( got != (int) size )
png_error( png, "Unexpected EOF" );
}
struct error_info
{
char *err;
const char *fn;
};
void PNG_Error( png_struct *png, const char *error )
{
CHECKPOINT;
error_info *info = (error_info *) png_get_error_ptr(png);
strncpy( info->err, error, 1024 );
info->err[1023] = 0;
LOG->Trace( "loading \"%s\": err: %s", info->fn, info->err );
longjmp( png_jmpbuf(png), 1 );
}
void PNG_Warning( png_struct *png, const char *warning )
{
CHECKPOINT;
error_info *info = (error_info *) png_get_io_ptr(png);
LOG->Trace( "loading \"%s\": warning: %s", info->fn, warning );
}
/* Since libpng forces us to use longjmp (gross!), this function shouldn't create any C++
* objects, and needs to watch out for memleaks. */
static RageSurface *RageSurface_Load_PNG( RageFile *f, const char *fn, char errorbuf[1024], bool bHeaderOnly )
{
error_info error;
error.err = errorbuf;
error.fn = fn;
png_struct *png = png_create_read_struct( PNG_LIBPNG_VER_STRING, &error, PNG_Error, PNG_Warning );
#if defined(XBOX)
while(png == NULL)
{
if(!vmem_Manager.DecommitLRU())
break;
png = png_create_read_struct( PNG_LIBPNG_VER_STRING, &error, PNG_Error, PNG_Warning );
}
#endif
if( png == NULL )
{
sprintf( errorbuf, "creating png_create_read_struct failed");
return NULL;
}
png_info *info_ptr = png_create_info_struct(png);
if( info_ptr == NULL )
{
png_destroy_read_struct( &png, NULL, NULL );
sprintf( errorbuf, "creating png_create_info_struct failed");
return NULL;
}
RageSurface *volatile img = NULL;
CHECKPOINT;
if( setjmp(png_jmpbuf(png) ))
{
png_destroy_read_struct( &png, &info_ptr, NULL );
delete img;
return NULL;
}
CHECKPOINT;
png_set_read_fn( png, f, RageFile_png_read );
png_read_info( png, info_ptr );
png_uint_32 width, height;
int bit_depth, color_type;
png_get_IHDR( png, info_ptr, &width, &height, &bit_depth, &color_type, NULL, NULL, NULL );
/* If bHeaderOnly is true, don't allocate the pixel storage space or decompress
* the image. Just return an empty surface with only the width and height set. */
if( bHeaderOnly )
{
CHECKPOINT;
img = CreateSurfaceFrom( width, height, 32, 0, 0, 0, 0, NULL, width*4 );
png_destroy_read_struct( &png, &info_ptr, NULL );
return img;
}
CHECKPOINT;
png_set_strip_16(png); /* 16bit->8bit */
png_set_packing( png ); /* 1,2,4 bit->8 bit */
/* Expand grayscale images to the full 8 bits from 1, 2, or 4 bits/pixel */
if( color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8 )
png_set_expand_gray_1_2_4_to_8( png );
/* These are set for type == PALETTE. */
RageSurfaceColor colors[256];
int iColorKey = -1;
/* We import three types of files: paletted, RGBX and RGBA. The only difference
* between RGBX and RGBA is that RGBX won't set the alpha mask, so it's easier
* to tell later on that there's no alpha (without actually having to do a pixel scan). */
enum { PALETTE, RGBX, RGBA } type;
switch( color_type )
{
case PNG_COLOR_TYPE_GRAY:
/* Fake PNG_COLOR_TYPE_GRAY. */
for( int i = 0; i < 256; ++i )
{
colors[i].r = colors[i].g = colors[i].b = (int8_t) i;
colors[i].a = 0xFF;
}
type = PALETTE;
break;
case PNG_COLOR_TYPE_GRAY_ALPHA:
type = RGBA;
png_set_gray_to_rgb( png );
break;
case PNG_COLOR_TYPE_PALETTE:
type = PALETTE;
break;
case PNG_COLOR_TYPE_RGB:
type = RGBX;
break;
case PNG_COLOR_TYPE_RGB_ALPHA:
type = RGBA;
break;
default:
FAIL_M(ssprintf( "%i", color_type) );
}
CHECKPOINT;
if( color_type == PNG_COLOR_TYPE_GRAY )
{
png_color_16 *trans;
if( png_get_tRNS( png, info_ptr, NULL, NULL, &trans ) == PNG_INFO_tRNS )
iColorKey = trans->gray;
}
else if( color_type == PNG_COLOR_TYPE_PALETTE )
{
int num_palette;
png_color *palette;
int ret = png_get_PLTE( png, info_ptr, &palette, &num_palette );
ASSERT( ret == PNG_INFO_PLTE );
png_byte *trans = NULL;
int num_trans = 0;
png_get_tRNS( png, info_ptr, &trans, &num_trans, NULL );
for( int i = 0; i < num_palette; ++i )
{
colors[i].r = palette[i].red;
colors[i].g = palette[i].green;
colors[i].b = palette[i].blue;
colors[i].a = 0xFF;
if( i < num_trans )
colors[i].a = trans[i];
}
}
else
{
/* If we have RGB image and tRNS, it's a color key. Just convert it to RGBA. */
if( png_get_valid(png, info_ptr, PNG_INFO_tRNS) )
{
/* We don't care about RGB color keys; just convert them to alpha. */
png_set_tRNS_to_alpha( png );
type = RGBA;
}
/* RGB->RGBX */
png_set_filler( png, 0xff, PNG_FILLER_AFTER );
}
png_set_interlace_handling( png );
CHECKPOINT;
png_read_update_info( png, info_ptr );
switch( type )
{
case PALETTE:
img = CreateSurface( width, height, 8, 0, 0, 0, 0 );
memcpy( img->fmt.palette->colors, colors, 256*sizeof(RageSurfaceColor) );
if( iColorKey != -1 )
img->format->palette->colors[ iColorKey ].a = 0;
break;
case RGBX:
case RGBA:
img = CreateSurface( width, height, 32,
Swap32BE( 0xFF000000 ),
Swap32BE( 0x00FF0000 ),
Swap32BE( 0x0000FF00 ),
Swap32BE( type == RGBA? 0x000000FF:0x00000000 ) );
break;
default:
FAIL_M(ssprintf( "%i", type) );
}
ASSERT( img );
/* alloca to prevent memleaks if libpng longjmps us */
png_byte **row_pointers = (png_byte **) alloca( sizeof(png_byte*) * height );
CHECKPOINT_M( ssprintf("%p",row_pointers) );
for( unsigned y = 0; y < height; ++y )
{
png_byte *p = (png_byte *) img->pixels;
row_pointers[y] = p + img->pitch*y;
}
CHECKPOINT;
png_read_image( png, row_pointers );
CHECKPOINT;
png_read_end( png, info_ptr );
png_destroy_read_struct( &png, &info_ptr, NULL );
return img;
}
};
RageSurfaceUtils::OpenResult RageSurface_Load_PNG( const RString &sPath, RageSurface *&ret, bool bHeaderOnly, RString &error )
{
RageFile f;
if( !f.Open( sPath ) )
{
error = f.GetError();
return RageSurfaceUtils::OPEN_FATAL_ERROR;
}
char errorbuf[1024];
ret = RageSurface_Load_PNG( &f, sPath, errorbuf, bHeaderOnly );
if( ret == NULL )
{
error = errorbuf;
return RageSurfaceUtils::OPEN_UNKNOWN_FILE_FORMAT; // XXX
}
return RageSurfaceUtils::OPEN_OK;
}
/*
* (c) 2004 Glenn Maynard
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, and/or sell copies of the Software, and to permit persons to
* whom the Software is furnished to do so, provided that the above
* copyright notice(s) and this permission notice appear in all copies of
* the Software and that both the above copyright notice(s) and this
* permission notice appear in supporting documentation.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
+168 -168
View File
@@ -1,168 +1,168 @@
#include "global.h"
#include "RageSurface_Save_PNG.h"
#include "RageSurface.h"
#include "RageSurfaceUtils.h"
#include "RageFile.h"
#include "RageLog.h"
#include "RageUtil.h"
#if defined(WINDOWS) || defined(_XBOX)
#include "libpng/include/png.h"
#if defined(_MSC_VER)
# if defined(_XBOX)
# pragma comment(lib, "libpng/lib/xboxlibpng.lib")
# else
# pragma comment(lib, "libpng/lib/libpng.lib")
# endif
#pragma warning(disable: 4611) /* interaction between '_setjmp' and C++ object destruction is non-portable */
#endif
#else
#include <png.h>
#endif
static void SafePngError( png_struct *pPng, const RString &sStr )
{
/* png_error will call PNG_Error, which will longjmp. If we just pass
* GetError().c_str() to it, a temporary may be created; since control
* never returns, it may never be destructed and leak. */
static char error[256];
strncpy( error, sStr, sizeof(error) );
error[sizeof(error)-1] = 0;
png_error( pPng, error );
}
static void RageFile_png_write( png_struct *pPng, png_byte *pData, png_size_t iSize )
{
RageFile *pFile = (RageFile *) png_get_io_ptr(pPng);
int iGot = pFile->Write( pData, iSize );
if( iGot == -1 )
SafePngError( pPng, pFile->GetError() );
}
static void RageFile_png_flush( png_struct *pPng )
{
RageFile *pFile = (RageFile *) png_get_io_ptr(pPng);
int iGot = pFile->Flush();
if( iGot == -1 )
SafePngError( pPng, pFile->GetError() );
}
struct error_info
{
char *szErr;
};
static void PNG_Error( png_struct *pPng, const char *szError )
{
error_info *pInfo = (error_info *) png_get_error_ptr(pPng);
strncpy( pInfo->szErr, szError, 1024 );
pInfo->szErr[1023] = 0;
longjmp( png_jmpbuf(pPng), 1 );
}
static void PNG_Warning( png_struct *png, const char *warning )
{
LOG->Trace( "saving PNG: warning: %s", warning );
}
/* Since libpng forces us to use longjmp, this function shouldn't create any C++
* objects, and needs to watch out for memleaks. */
static bool RageSurface_Save_PNG( RageFile &f, char szErrorbuf[1024], RageSurface *pImgIn )
{
bool bAlpha = pImgIn->format->Amask != 0;
RageSurface *pImg;
bool bDeleteImg = RageSurfaceUtils::ConvertSurface( pImgIn, pImg, pImgIn->w, pImgIn->h, 32,
Swap32BE( 0xFF000000 ),
Swap32BE( 0x00FF0000 ),
Swap32BE( 0x0000FF00 ),
Swap32BE( 0x000000FF ) );
if( !bDeleteImg )
pImg = pImgIn;
error_info error;
error.szErr = szErrorbuf;
png_struct *pPng = png_create_write_struct( PNG_LIBPNG_VER_STRING, &error, PNG_Error, PNG_Warning );
if( pPng == NULL )
{
sprintf( szErrorbuf, "creating png_create_write_struct failed");
return false;
}
png_info *pInfo = png_create_info_struct(pPng);
if( pInfo == NULL )
{
png_destroy_read_struct( &pPng, NULL, NULL );
if( bDeleteImg )
delete pImg;
sprintf( szErrorbuf, "creating png_create_info_struct failed");
return false;
}
if( setjmp(png_jmpbuf(pPng)) )
{
png_destroy_read_struct( &pPng, &pInfo, NULL );
return false;
}
png_set_write_fn( pPng, &f, RageFile_png_write, RageFile_png_flush );
png_set_compression_level( pPng, 1 );
png_set_IHDR( pPng, pInfo, pImg->w, pImg->h, 8, bAlpha? PNG_COLOR_TYPE_RGBA:PNG_COLOR_TYPE_RGB,
PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE );
png_write_info( pPng, pInfo );
png_set_filler( pPng, 0, PNG_FILLER_AFTER );
png_byte *pixels = (png_byte *) pImg->pixels;
for( int y = 0; y < pImg->h; y++ )
png_write_row( pPng, pixels + pImg->pitch*y );
png_write_end( pPng, pInfo );
png_destroy_write_struct( &pPng, &pInfo );
/* Free the converted image. */
if( bDeleteImg )
delete pImg;
return true;
}
bool RageSurfaceUtils::SavePNG( RageSurface *pImg, RageFile &f, RString &sError )
{
char szErrorBuf[1024];
if( !RageSurface_Save_PNG(f, szErrorBuf, pImg) )
{
sError = szErrorBuf;
return false;
}
return true;
}
/*
* (c) 2004-2006 Glenn Maynard
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, and/or sell copies of the Software, and to permit persons to
* whom the Software is furnished to do so, provided that the above
* copyright notice(s) and this permission notice appear in all copies of
* the Software and that both the above copyright notice(s) and this
* permission notice appear in supporting documentation.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
#include "global.h"
#include "RageSurface_Save_PNG.h"
#include "RageSurface.h"
#include "RageSurfaceUtils.h"
#include "RageFile.h"
#include "RageLog.h"
#include "RageUtil.h"
#if defined(WINDOWS) || defined(_XBOX)
#include "libpng/include/png.h"
#if defined(_MSC_VER)
# if defined(_XBOX)
# pragma comment(lib, "libpng/lib/xboxlibpng.lib")
# else
# pragma comment(lib, "libpng/lib/libpng.lib")
# endif
#pragma warning(disable: 4611) /* interaction between '_setjmp' and C++ object destruction is non-portable */
#endif
#else
#include <png.h>
#endif
static void SafePngError( png_struct *pPng, const RString &sStr )
{
/* png_error will call PNG_Error, which will longjmp. If we just pass
* GetError().c_str() to it, a temporary may be created; since control
* never returns, it may never be destructed and leak. */
static char error[256];
strncpy( error, sStr, sizeof(error) );
error[sizeof(error)-1] = 0;
png_error( pPng, error );
}
static void RageFile_png_write( png_struct *pPng, png_byte *pData, png_size_t iSize )
{
RageFile *pFile = (RageFile *) png_get_io_ptr(pPng);
int iGot = pFile->Write( pData, iSize );
if( iGot == -1 )
SafePngError( pPng, pFile->GetError() );
}
static void RageFile_png_flush( png_struct *pPng )
{
RageFile *pFile = (RageFile *) png_get_io_ptr(pPng);
int iGot = pFile->Flush();
if( iGot == -1 )
SafePngError( pPng, pFile->GetError() );
}
struct error_info
{
char *szErr;
};
static void PNG_Error( png_struct *pPng, const char *szError )
{
error_info *pInfo = (error_info *) png_get_error_ptr(pPng);
strncpy( pInfo->szErr, szError, 1024 );
pInfo->szErr[1023] = 0;
longjmp( png_jmpbuf(pPng), 1 );
}
static void PNG_Warning( png_struct *png, const char *warning )
{
LOG->Trace( "saving PNG: warning: %s", warning );
}
/* Since libpng forces us to use longjmp, this function shouldn't create any C++
* objects, and needs to watch out for memleaks. */
static bool RageSurface_Save_PNG( RageFile &f, char szErrorbuf[1024], RageSurface *pImgIn )
{
bool bAlpha = pImgIn->format->Amask != 0;
RageSurface *pImg;
bool bDeleteImg = RageSurfaceUtils::ConvertSurface( pImgIn, pImg, pImgIn->w, pImgIn->h, 32,
Swap32BE( 0xFF000000 ),
Swap32BE( 0x00FF0000 ),
Swap32BE( 0x0000FF00 ),
Swap32BE( 0x000000FF ) );
if( !bDeleteImg )
pImg = pImgIn;
error_info error;
error.szErr = szErrorbuf;
png_struct *pPng = png_create_write_struct( PNG_LIBPNG_VER_STRING, &error, PNG_Error, PNG_Warning );
if( pPng == NULL )
{
sprintf( szErrorbuf, "creating png_create_write_struct failed");
return false;
}
png_info *pInfo = png_create_info_struct(pPng);
if( pInfo == NULL )
{
png_destroy_read_struct( &pPng, NULL, NULL );
if( bDeleteImg )
delete pImg;
sprintf( szErrorbuf, "creating png_create_info_struct failed");
return false;
}
if( setjmp(png_jmpbuf(pPng)) )
{
png_destroy_read_struct( &pPng, &pInfo, NULL );
return false;
}
png_set_write_fn( pPng, &f, RageFile_png_write, RageFile_png_flush );
png_set_compression_level( pPng, 1 );
png_set_IHDR( pPng, pInfo, pImg->w, pImg->h, 8, bAlpha? PNG_COLOR_TYPE_RGBA:PNG_COLOR_TYPE_RGB,
PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE );
png_write_info( pPng, pInfo );
png_set_filler( pPng, 0, PNG_FILLER_AFTER );
png_byte *pixels = (png_byte *) pImg->pixels;
for( int y = 0; y < pImg->h; y++ )
png_write_row( pPng, pixels + pImg->pitch*y );
png_write_end( pPng, pInfo );
png_destroy_write_struct( &pPng, &pInfo );
/* Free the converted image. */
if( bDeleteImg )
delete pImg;
return true;
}
bool RageSurfaceUtils::SavePNG( RageSurface *pImg, RageFile &f, RString &sError )
{
char szErrorBuf[1024];
if( !RageSurface_Save_PNG(f, szErrorBuf, pImg) )
{
sError = szErrorBuf;
return false;
}
return true;
}
/*
* (c) 2004-2006 Glenn Maynard
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, and/or sell copies of the Software, and to permit persons to
* whom the Software is furnished to do so, provided that the above
* copyright notice(s) and this permission notice appear in all copies of
* the Software and that both the above copyright notice(s) and this
* permission notice appear in supporting documentation.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
+447 -447
View File
@@ -1,447 +1,447 @@
#include "global.h"
#include "InputHandler_Linux_Event.h"
#include "RageLog.h"
#include "RageUtil.h"
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <linux/input.h>
REGISTER_INPUT_HANDLER_CLASS2( Event, Linux_Event );
bool InputHandler_Linux_Event::m_bFoundAnyJoysticks;
static RString BustypeToString( int iBus )
{
switch( iBus )
{
// case BUS_ADB:
// case BUS_AMIGA: return "amiga input";
case BUS_BLUETOOTH: return "Bluetooth";
case BUS_GAMEPORT: return "gameport";
// case BUS_HIL:
// case BUS_HOST:
// case BUS_I2C:
case BUS_I8042: return "keyboard";
case BUS_ISA: return "ISA";
case BUS_ISAPNP: return "ISAPNP";
case BUS_PARPORT: return "parallel port";
case BUS_PCI: return "PCI";
case BUS_RS232: return "serial port";
case BUS_USB: return "USB";
case BUS_XTKBD: return "XT keyboard";
default: return ssprintf("unknown bus %x", iBus);
}
}
struct EventDevice
{
EventDevice();
~EventDevice();
bool Open( RString sFile, InputDevice dev );
bool IsOpen() const { return m_iFD != -1; }
void Close()
{
if( m_iFD != -1 )
close( m_iFD );
m_iFD = -1;
}
int m_iFD;
RString m_sPath;
RString m_sName;
InputDevice m_Dev;
int aiAbsMin[ABS_MAX];
int aiAbsMax[ABS_MAX];
DeviceButton aiAbsMappingHigh[ABS_MAX];
DeviceButton aiAbsMappingLow[ABS_MAX];
};
static vector<EventDevice *> g_apEventDevices;
/* Return true if the numbered event device exists. sysfs may not always be
* there; return false if we don't know. */
static bool EventDeviceExists( int iNum )
{
RString sDir = ssprintf( "/sys/class" );
struct stat st;
if( stat(sDir, &st) == -1 )
return true;
RString sFile = ssprintf( "/sys/class/input/event%i", iNum );
return stat(sFile, &st) == 0;
}
static bool BitIsSet( const uint8_t *pArray, uint32_t iBit )
{
return !!(pArray[iBit/8] & (1<<(iBit%8)));
}
EventDevice::EventDevice()
{
m_iFD = -1;
}
bool EventDevice::Open( RString sFile, InputDevice dev )
{
m_sPath = sFile;
m_Dev = dev;
m_iFD = open( sFile, O_RDWR );
if( m_iFD == -1 )
{
if( errno == ENODEV )
return false;
if( !EventDeviceExists(m_iFD) )
return false;
LOG->Warn( "Error opening %s: %s", sFile.c_str(), strerror(errno) );
return false;
}
static bool bLogged = false;
if( !bLogged )
{
bLogged = true;
int iVersion;
if( ioctl(m_iFD, EVIOCGVERSION, &iVersion) == -1 )
LOG->Warn( "ioctl(EVIOCGVERSION): %s", strerror(errno) );
else
LOG->Info( "Event driver: v%i.%i.%i", (iVersion >> 16) & 0xFF, (iVersion >> 8) & 0xFF, iVersion & 0xFF );
}
char szName[1024];
if( ioctl(m_iFD, EVIOCGNAME(sizeof(szName)), szName) == -1 )
{
LOG->Warn( "ioctl(EVIOCGNAME): %s", strerror(errno) );
m_sName = "(unknown)";
}
else
{
m_sName = szName;
}
input_id DevInfo;
if( ioctl(m_iFD, EVIOCGID, &DevInfo) == -1 )
{
LOG->Warn( "ioctl(EVIOCGID): %s", strerror(errno) );
}
else
{
LOG->Info( "Input device: %s: %s device, ID %04x:%04x, version %x: %s", sFile.c_str(),
BustypeToString(DevInfo.bustype).c_str(), DevInfo.vendor, DevInfo.product,
DevInfo.version, m_sName.c_str() );
}
uint8_t iABSMask[ABS_MAX/8 + 1];
memset( iABSMask, 0, sizeof(iABSMask) );
if( ioctl(m_iFD, EVIOCGBIT(EV_ABS, sizeof(iABSMask)), iABSMask) < 0 )
LOG->Warn( "ioctl(EVIOCGBIT(EV_ABS)): %s", strerror(errno) );
if( !BitIsSet(iABSMask, ABS_X) && !BitIsSet(iABSMask, ABS_THROTTLE) && !BitIsSet(iABSMask, ABS_WHEEL) )
{
LOG->Info( " Not a joystick; ignored" );
Close();
return false;
}
uint8_t iKeyMask[KEY_MAX/8 + 1];
memset( iKeyMask, 0, sizeof(iKeyMask) );
if( ioctl(m_iFD, EVIOCGBIT(EV_KEY, sizeof(iKeyMask)), iKeyMask) < 0 )
LOG->Warn( "ioctl(EVIOCGBIT(EV_KEY)): %s", strerror(errno) );
uint8_t iEventTypes[EV_MAX/8];
memset( iEventTypes, 0, sizeof(iEventTypes) );
if( ioctl(m_iFD, EVIOCGBIT(0, EV_MAX), iEventTypes) == -1 )
LOG->Warn( "ioctl(EV_MAX): %s", strerror(errno) );
{
vector<RString> setEventTypes;
if( BitIsSet(iEventTypes, EV_SYN) ) setEventTypes.push_back( "syn" );
if( BitIsSet(iEventTypes, EV_KEY) ) setEventTypes.push_back( "key" );
if( BitIsSet(iEventTypes, EV_REL) ) setEventTypes.push_back( "rel" );
if( BitIsSet(iEventTypes, EV_ABS) ) setEventTypes.push_back( "abs" );
if( BitIsSet(iEventTypes, EV_MSC) ) setEventTypes.push_back( "misc" );
if( BitIsSet(iEventTypes, EV_SW) ) setEventTypes.push_back( "sw" );
if( BitIsSet(iEventTypes, EV_LED) ) setEventTypes.push_back( "led" );
if( BitIsSet(iEventTypes, EV_SND) ) setEventTypes.push_back( "snd" );
if( BitIsSet(iEventTypes, EV_REP) ) setEventTypes.push_back( "rep" );
if( BitIsSet(iEventTypes, EV_FF) ) setEventTypes.push_back( "ff" );
if( BitIsSet(iEventTypes, EV_PWR) ) setEventTypes.push_back( "pwr" );
if( BitIsSet(iEventTypes, EV_FF_STATUS) ) setEventTypes.push_back( "ff_status" );
LOG->Info( " Event types: %s", join(", ", setEventTypes).c_str() );
}
int iTotalKeys = 0;
for( int i = 0; i < KEY_MAX; ++i )
{
if( !BitIsSet(iKeyMask, i) )
continue;
++iTotalKeys;
}
int iTotalAxes = 0;
const DeviceButton iExtraAxes[] = { JOY_LEFT_2, JOY_UP_2, JOY_AUX_1, JOY_AUX_3 };
int iNextExtraAxis = 0;
for( int i = 0; i < ABS_MAX; ++i )
{
if( !BitIsSet(iABSMask, i) )
continue;
struct input_absinfo absinfo;
if( ioctl(m_iFD, EVIOCGABS(i), &absinfo) < 0 )
{
LOG->Warn( "ioctl(EVIOCGABS): %s", strerror(errno) );
continue;
}
//LOG->Info( " Axis %i: min: %i; max: %i; fuzz: %i; flat: %i",
// i, absinfo.minimum, absinfo.maximum, absinfo.fuzz, absinfo.flat );
aiAbsMin[i] = absinfo.minimum;
aiAbsMax[i] = absinfo.maximum;
aiAbsMappingHigh[i] = enum_add2(JOY_RIGHT, 2*i);
aiAbsMappingLow[i] = enum_add2(JOY_LEFT, 2*i);
if( i == ABS_X )
{
aiAbsMappingHigh[i] = JOY_RIGHT;
aiAbsMappingLow[i] = JOY_LEFT;
}
else if( i == ABS_Y )
{
aiAbsMappingHigh[i] = JOY_DOWN;
aiAbsMappingLow[i] = JOY_UP;
}
else if( i == ABS_Z )
{
aiAbsMappingHigh[i] = JOY_Z_DOWN;
aiAbsMappingLow[i] = JOY_Z_UP;
}
else if( i == ABS_RX )
{
aiAbsMappingHigh[i] = JOY_ROT_RIGHT;
aiAbsMappingLow[i] = JOY_ROT_LEFT;
}
else if( i == ABS_RY )
{
aiAbsMappingHigh[i] = JOY_ROT_DOWN;
aiAbsMappingLow[i] = JOY_ROT_UP;
}
else if( i == ABS_RZ )
{
aiAbsMappingHigh[i] = JOY_ROT_Z_DOWN;
aiAbsMappingLow[i] = JOY_ROT_Z_UP;
}
else if( i == ABS_HAT0X )
{
aiAbsMappingHigh[i] = JOY_HAT_RIGHT;
aiAbsMappingLow[i] = JOY_HAT_LEFT;
}
else if( i == ABS_HAT0Y )
{
aiAbsMappingHigh[i] = JOY_HAT_UP;
aiAbsMappingLow[i] = JOY_HAT_DOWN;
}
else
{
if( iNextExtraAxis < (int) ARRAYLEN(iExtraAxes) )
{
aiAbsMappingLow[i] = iExtraAxes[iNextExtraAxis];
aiAbsMappingHigh[i] = enum_add2( aiAbsMappingLow[i], 1 );
++iNextExtraAxis;
}
}
++iTotalAxes;
}
LOG->Info( " Total keys: %i; total axes: %i", iTotalKeys, iTotalAxes );
return true;
}
EventDevice::~EventDevice()
{
Close();
}
InputHandler_Linux_Event::InputHandler_Linux_Event()
{
if( InputHandler_Linux_Event::m_bFoundAnyJoysticks )
{
LOG->Trace( "InputHandler_Linux_Event disabled (joystick driver already loaded)" );
return;
}
/* Permission problems are likely. We want to warn about them only if there's actually
* an underlying device, but if we can't open the device, the only way we can tell if
* there'd be anything there is sysfs. That won't always be there. */
m_bFoundAnyJoysticks = false;
InputDevice NextDevice = DEVICE_JOY1;
for( int i = 0; i < 64; ++i )
{
RString sFile = ssprintf( "/dev/input/event%i", i );
g_apEventDevices.push_back( new EventDevice );
EventDevice *pDev = g_apEventDevices.back();
if( !pDev->Open(sFile, NextDevice) )
{
delete pDev;
g_apEventDevices.pop_back();
continue;
}
NextDevice = enum_add2(NextDevice, 1);
m_bFoundAnyJoysticks = true;
}
m_bShutdown = false;
if( m_bFoundAnyJoysticks )
{
m_InputThread.SetName( "Event input thread" );
m_InputThread.Create( InputThread_Start, this );
/* We loaded joysticks, so disable joydev. */
}
}
InputHandler_Linux_Event::~InputHandler_Linux_Event()
{
if( m_InputThread.IsCreated() )
{
m_bShutdown = true;
LOG->Trace( "Shutting down joystick thread ..." );
m_InputThread.Wait();
LOG->Trace( "Joystick thread shut down." );
}
for( int i = 0; i < (int) g_apEventDevices.size(); ++i )
delete g_apEventDevices[i];
g_apEventDevices.clear();
}
int InputHandler_Linux_Event::InputThread_Start( void *p )
{
((InputHandler_Linux_Event *) p)->InputThread();
return 0;
}
void InputHandler_Linux_Event::InputThread()
{
while( !m_bShutdown )
{
fd_set fdset;
FD_ZERO( &fdset );
int iMaxFD = -1;
for( int i = 0; i < (int) g_apEventDevices.size(); ++i )
{
int iFD = g_apEventDevices[i]->m_iFD;
if( !g_apEventDevices[i]->IsOpen() )
continue;
FD_SET( iFD, &fdset );
iMaxFD = max( iMaxFD, iFD );
}
if( iMaxFD == -1 )
break;
struct timeval zero = {0,100000};
if( select(iMaxFD+1, &fdset, NULL, NULL, &zero) <= 0 )
continue;
RageTimer now;
for( int i = 0; i < (int) g_apEventDevices.size(); ++i )
{
if( !g_apEventDevices[i]->IsOpen() )
continue;
if( !FD_ISSET(g_apEventDevices[i]->m_iFD, &fdset) )
continue;
input_event event;
int ret = read( g_apEventDevices[i]->m_iFD, &event, sizeof(event) );
if( ret == -1 )
{
LOG->Warn( "Error reading from %s: %s; disabled", g_apEventDevices[i]->m_sPath.c_str(), strerror(errno) );
g_apEventDevices[i]->Close();
continue;
}
if( ret != sizeof(event) )
{
LOG->Warn("Unexpected packet (size %i != %i) from joystick %i; disabled", ret, (int)sizeof(event), i);
g_apEventDevices[i]->Close();
continue;
}
switch (event.type) {
case EV_KEY: {
int iNum = event.code;
// In 2.6.11 using an EMS USB2, the event number for P1 Tri (the first button)
// is being reported as 32 instead of 0. Correct for this.
wrap( iNum, 32 ); // max number of joystick buttons. Make this a constant?
ButtonPressed( DeviceInput(g_apEventDevices[i]->m_Dev, enum_add2(JOY_BUTTON_1, iNum), event.value != 0, now) );
break;
}
case EV_ABS: {
ASSERT_M( event.code < ABS_MAX, ssprintf("%i", event.code) );
DeviceButton neg = g_apEventDevices[i]->aiAbsMappingLow[event.code];
DeviceButton pos = g_apEventDevices[i]->aiAbsMappingHigh[event.code];
float l = SCALE( int(event.value), (float) g_apEventDevices[i]->aiAbsMin[i], (float) g_apEventDevices[i]->aiAbsMax[i], -1.0f, 1.0f );
ButtonPressed( DeviceInput(g_apEventDevices[i]->m_Dev, neg, max(-l,0), now) );
ButtonPressed( DeviceInput(g_apEventDevices[i]->m_Dev, pos, max(+l,0), now) );
break;
}
}
}
}
InputHandler::UpdateTimer();
}
void InputHandler_Linux_Event::GetDevicesAndDescriptions( vector<InputDeviceInfo>& vDevicesOut )
{
for( unsigned i = 0; i < g_apEventDevices.size(); ++i )
{
EventDevice *pDev = g_apEventDevices[i];
vDevicesOut.push_back( InputDeviceInfo(pDev->m_Dev, pDev->m_sName) );
}
}
/*
* (c) 2003-2008 Glenn Maynard
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, and/or sell copies of the Software, and to permit persons to
* whom the Software is furnished to do so, provided that the above
* copyright notice(s) and this permission notice appear in all copies of
* the Software and that both the above copyright notice(s) and this
* permission notice appear in supporting documentation.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
#include "global.h"
#include "InputHandler_Linux_Event.h"
#include "RageLog.h"
#include "RageUtil.h"
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <linux/input.h>
REGISTER_INPUT_HANDLER_CLASS2( Event, Linux_Event );
bool InputHandler_Linux_Event::m_bFoundAnyJoysticks;
static RString BustypeToString( int iBus )
{
switch( iBus )
{
// case BUS_ADB:
// case BUS_AMIGA: return "amiga input";
case BUS_BLUETOOTH: return "Bluetooth";
case BUS_GAMEPORT: return "gameport";
// case BUS_HIL:
// case BUS_HOST:
// case BUS_I2C:
case BUS_I8042: return "keyboard";
case BUS_ISA: return "ISA";
case BUS_ISAPNP: return "ISAPNP";
case BUS_PARPORT: return "parallel port";
case BUS_PCI: return "PCI";
case BUS_RS232: return "serial port";
case BUS_USB: return "USB";
case BUS_XTKBD: return "XT keyboard";
default: return ssprintf("unknown bus %x", iBus);
}
}
struct EventDevice
{
EventDevice();
~EventDevice();
bool Open( RString sFile, InputDevice dev );
bool IsOpen() const { return m_iFD != -1; }
void Close()
{
if( m_iFD != -1 )
close( m_iFD );
m_iFD = -1;
}
int m_iFD;
RString m_sPath;
RString m_sName;
InputDevice m_Dev;
int aiAbsMin[ABS_MAX];
int aiAbsMax[ABS_MAX];
DeviceButton aiAbsMappingHigh[ABS_MAX];
DeviceButton aiAbsMappingLow[ABS_MAX];
};
static vector<EventDevice *> g_apEventDevices;
/* Return true if the numbered event device exists. sysfs may not always be
* there; return false if we don't know. */
static bool EventDeviceExists( int iNum )
{
RString sDir = ssprintf( "/sys/class" );
struct stat st;
if( stat(sDir, &st) == -1 )
return true;
RString sFile = ssprintf( "/sys/class/input/event%i", iNum );
return stat(sFile, &st) == 0;
}
static bool BitIsSet( const uint8_t *pArray, uint32_t iBit )
{
return !!(pArray[iBit/8] & (1<<(iBit%8)));
}
EventDevice::EventDevice()
{
m_iFD = -1;
}
bool EventDevice::Open( RString sFile, InputDevice dev )
{
m_sPath = sFile;
m_Dev = dev;
m_iFD = open( sFile, O_RDWR );
if( m_iFD == -1 )
{
if( errno == ENODEV )
return false;
if( !EventDeviceExists(m_iFD) )
return false;
LOG->Warn( "Error opening %s: %s", sFile.c_str(), strerror(errno) );
return false;
}
static bool bLogged = false;
if( !bLogged )
{
bLogged = true;
int iVersion;
if( ioctl(m_iFD, EVIOCGVERSION, &iVersion) == -1 )
LOG->Warn( "ioctl(EVIOCGVERSION): %s", strerror(errno) );
else
LOG->Info( "Event driver: v%i.%i.%i", (iVersion >> 16) & 0xFF, (iVersion >> 8) & 0xFF, iVersion & 0xFF );
}
char szName[1024];
if( ioctl(m_iFD, EVIOCGNAME(sizeof(szName)), szName) == -1 )
{
LOG->Warn( "ioctl(EVIOCGNAME): %s", strerror(errno) );
m_sName = "(unknown)";
}
else
{
m_sName = szName;
}
input_id DevInfo;
if( ioctl(m_iFD, EVIOCGID, &DevInfo) == -1 )
{
LOG->Warn( "ioctl(EVIOCGID): %s", strerror(errno) );
}
else
{
LOG->Info( "Input device: %s: %s device, ID %04x:%04x, version %x: %s", sFile.c_str(),
BustypeToString(DevInfo.bustype).c_str(), DevInfo.vendor, DevInfo.product,
DevInfo.version, m_sName.c_str() );
}
uint8_t iABSMask[ABS_MAX/8 + 1];
memset( iABSMask, 0, sizeof(iABSMask) );
if( ioctl(m_iFD, EVIOCGBIT(EV_ABS, sizeof(iABSMask)), iABSMask) < 0 )
LOG->Warn( "ioctl(EVIOCGBIT(EV_ABS)): %s", strerror(errno) );
if( !BitIsSet(iABSMask, ABS_X) && !BitIsSet(iABSMask, ABS_THROTTLE) && !BitIsSet(iABSMask, ABS_WHEEL) )
{
LOG->Info( " Not a joystick; ignored" );
Close();
return false;
}
uint8_t iKeyMask[KEY_MAX/8 + 1];
memset( iKeyMask, 0, sizeof(iKeyMask) );
if( ioctl(m_iFD, EVIOCGBIT(EV_KEY, sizeof(iKeyMask)), iKeyMask) < 0 )
LOG->Warn( "ioctl(EVIOCGBIT(EV_KEY)): %s", strerror(errno) );
uint8_t iEventTypes[EV_MAX/8];
memset( iEventTypes, 0, sizeof(iEventTypes) );
if( ioctl(m_iFD, EVIOCGBIT(0, EV_MAX), iEventTypes) == -1 )
LOG->Warn( "ioctl(EV_MAX): %s", strerror(errno) );
{
vector<RString> setEventTypes;
if( BitIsSet(iEventTypes, EV_SYN) ) setEventTypes.push_back( "syn" );
if( BitIsSet(iEventTypes, EV_KEY) ) setEventTypes.push_back( "key" );
if( BitIsSet(iEventTypes, EV_REL) ) setEventTypes.push_back( "rel" );
if( BitIsSet(iEventTypes, EV_ABS) ) setEventTypes.push_back( "abs" );
if( BitIsSet(iEventTypes, EV_MSC) ) setEventTypes.push_back( "misc" );
if( BitIsSet(iEventTypes, EV_SW) ) setEventTypes.push_back( "sw" );
if( BitIsSet(iEventTypes, EV_LED) ) setEventTypes.push_back( "led" );
if( BitIsSet(iEventTypes, EV_SND) ) setEventTypes.push_back( "snd" );
if( BitIsSet(iEventTypes, EV_REP) ) setEventTypes.push_back( "rep" );
if( BitIsSet(iEventTypes, EV_FF) ) setEventTypes.push_back( "ff" );
if( BitIsSet(iEventTypes, EV_PWR) ) setEventTypes.push_back( "pwr" );
if( BitIsSet(iEventTypes, EV_FF_STATUS) ) setEventTypes.push_back( "ff_status" );
LOG->Info( " Event types: %s", join(", ", setEventTypes).c_str() );
}
int iTotalKeys = 0;
for( int i = 0; i < KEY_MAX; ++i )
{
if( !BitIsSet(iKeyMask, i) )
continue;
++iTotalKeys;
}
int iTotalAxes = 0;
const DeviceButton iExtraAxes[] = { JOY_LEFT_2, JOY_UP_2, JOY_AUX_1, JOY_AUX_3 };
int iNextExtraAxis = 0;
for( int i = 0; i < ABS_MAX; ++i )
{
if( !BitIsSet(iABSMask, i) )
continue;
struct input_absinfo absinfo;
if( ioctl(m_iFD, EVIOCGABS(i), &absinfo) < 0 )
{
LOG->Warn( "ioctl(EVIOCGABS): %s", strerror(errno) );
continue;
}
//LOG->Info( " Axis %i: min: %i; max: %i; fuzz: %i; flat: %i",
// i, absinfo.minimum, absinfo.maximum, absinfo.fuzz, absinfo.flat );
aiAbsMin[i] = absinfo.minimum;
aiAbsMax[i] = absinfo.maximum;
aiAbsMappingHigh[i] = enum_add2(JOY_RIGHT, 2*i);
aiAbsMappingLow[i] = enum_add2(JOY_LEFT, 2*i);
if( i == ABS_X )
{
aiAbsMappingHigh[i] = JOY_RIGHT;
aiAbsMappingLow[i] = JOY_LEFT;
}
else if( i == ABS_Y )
{
aiAbsMappingHigh[i] = JOY_DOWN;
aiAbsMappingLow[i] = JOY_UP;
}
else if( i == ABS_Z )
{
aiAbsMappingHigh[i] = JOY_Z_DOWN;
aiAbsMappingLow[i] = JOY_Z_UP;
}
else if( i == ABS_RX )
{
aiAbsMappingHigh[i] = JOY_ROT_RIGHT;
aiAbsMappingLow[i] = JOY_ROT_LEFT;
}
else if( i == ABS_RY )
{
aiAbsMappingHigh[i] = JOY_ROT_DOWN;
aiAbsMappingLow[i] = JOY_ROT_UP;
}
else if( i == ABS_RZ )
{
aiAbsMappingHigh[i] = JOY_ROT_Z_DOWN;
aiAbsMappingLow[i] = JOY_ROT_Z_UP;
}
else if( i == ABS_HAT0X )
{
aiAbsMappingHigh[i] = JOY_HAT_RIGHT;
aiAbsMappingLow[i] = JOY_HAT_LEFT;
}
else if( i == ABS_HAT0Y )
{
aiAbsMappingHigh[i] = JOY_HAT_UP;
aiAbsMappingLow[i] = JOY_HAT_DOWN;
}
else
{
if( iNextExtraAxis < (int) ARRAYLEN(iExtraAxes) )
{
aiAbsMappingLow[i] = iExtraAxes[iNextExtraAxis];
aiAbsMappingHigh[i] = enum_add2( aiAbsMappingLow[i], 1 );
++iNextExtraAxis;
}
}
++iTotalAxes;
}
LOG->Info( " Total keys: %i; total axes: %i", iTotalKeys, iTotalAxes );
return true;
}
EventDevice::~EventDevice()
{
Close();
}
InputHandler_Linux_Event::InputHandler_Linux_Event()
{
if( InputHandler_Linux_Event::m_bFoundAnyJoysticks )
{
LOG->Trace( "InputHandler_Linux_Event disabled (joystick driver already loaded)" );
return;
}
/* Permission problems are likely. We want to warn about them only if there's actually
* an underlying device, but if we can't open the device, the only way we can tell if
* there'd be anything there is sysfs. That won't always be there. */
m_bFoundAnyJoysticks = false;
InputDevice NextDevice = DEVICE_JOY1;
for( int i = 0; i < 64; ++i )
{
RString sFile = ssprintf( "/dev/input/event%i", i );
g_apEventDevices.push_back( new EventDevice );
EventDevice *pDev = g_apEventDevices.back();
if( !pDev->Open(sFile, NextDevice) )
{
delete pDev;
g_apEventDevices.pop_back();
continue;
}
NextDevice = enum_add2(NextDevice, 1);
m_bFoundAnyJoysticks = true;
}
m_bShutdown = false;
if( m_bFoundAnyJoysticks )
{
m_InputThread.SetName( "Event input thread" );
m_InputThread.Create( InputThread_Start, this );
/* We loaded joysticks, so disable joydev. */
}
}
InputHandler_Linux_Event::~InputHandler_Linux_Event()
{
if( m_InputThread.IsCreated() )
{
m_bShutdown = true;
LOG->Trace( "Shutting down joystick thread ..." );
m_InputThread.Wait();
LOG->Trace( "Joystick thread shut down." );
}
for( int i = 0; i < (int) g_apEventDevices.size(); ++i )
delete g_apEventDevices[i];
g_apEventDevices.clear();
}
int InputHandler_Linux_Event::InputThread_Start( void *p )
{
((InputHandler_Linux_Event *) p)->InputThread();
return 0;
}
void InputHandler_Linux_Event::InputThread()
{
while( !m_bShutdown )
{
fd_set fdset;
FD_ZERO( &fdset );
int iMaxFD = -1;
for( int i = 0; i < (int) g_apEventDevices.size(); ++i )
{
int iFD = g_apEventDevices[i]->m_iFD;
if( !g_apEventDevices[i]->IsOpen() )
continue;
FD_SET( iFD, &fdset );
iMaxFD = max( iMaxFD, iFD );
}
if( iMaxFD == -1 )
break;
struct timeval zero = {0,100000};
if( select(iMaxFD+1, &fdset, NULL, NULL, &zero) <= 0 )
continue;
RageTimer now;
for( int i = 0; i < (int) g_apEventDevices.size(); ++i )
{
if( !g_apEventDevices[i]->IsOpen() )
continue;
if( !FD_ISSET(g_apEventDevices[i]->m_iFD, &fdset) )
continue;
input_event event;
int ret = read( g_apEventDevices[i]->m_iFD, &event, sizeof(event) );
if( ret == -1 )
{
LOG->Warn( "Error reading from %s: %s; disabled", g_apEventDevices[i]->m_sPath.c_str(), strerror(errno) );
g_apEventDevices[i]->Close();
continue;
}
if( ret != sizeof(event) )
{
LOG->Warn("Unexpected packet (size %i != %i) from joystick %i; disabled", ret, (int)sizeof(event), i);
g_apEventDevices[i]->Close();
continue;
}
switch (event.type) {
case EV_KEY: {
int iNum = event.code;
// In 2.6.11 using an EMS USB2, the event number for P1 Tri (the first button)
// is being reported as 32 instead of 0. Correct for this.
wrap( iNum, 32 ); // max number of joystick buttons. Make this a constant?
ButtonPressed( DeviceInput(g_apEventDevices[i]->m_Dev, enum_add2(JOY_BUTTON_1, iNum), event.value != 0, now) );
break;
}
case EV_ABS: {
ASSERT_M( event.code < ABS_MAX, ssprintf("%i", event.code) );
DeviceButton neg = g_apEventDevices[i]->aiAbsMappingLow[event.code];
DeviceButton pos = g_apEventDevices[i]->aiAbsMappingHigh[event.code];
float l = SCALE( int(event.value), (float) g_apEventDevices[i]->aiAbsMin[i], (float) g_apEventDevices[i]->aiAbsMax[i], -1.0f, 1.0f );
ButtonPressed( DeviceInput(g_apEventDevices[i]->m_Dev, neg, max(-l,0), now) );
ButtonPressed( DeviceInput(g_apEventDevices[i]->m_Dev, pos, max(+l,0), now) );
break;
}
}
}
}
InputHandler::UpdateTimer();
}
void InputHandler_Linux_Event::GetDevicesAndDescriptions( vector<InputDeviceInfo>& vDevicesOut )
{
for( unsigned i = 0; i < g_apEventDevices.size(); ++i )
{
EventDevice *pDev = g_apEventDevices[i];
vDevicesOut.push_back( InputDeviceInfo(pDev->m_Dev, pDev->m_sName) );
}
}
/*
* (c) 2003-2008 Glenn Maynard
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, and/or sell copies of the Software, and to permit persons to
* whom the Software is furnished to do so, provided that the above
* copyright notice(s) and this permission notice appear in all copies of
* the Software and that both the above copyright notice(s) and this
* permission notice appear in supporting documentation.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
@@ -1,227 +1,227 @@
#include "global.h"
#include "InputHandler_Linux_Joystick.h"
#include "InputHandler_Linux_Event.h" // for m_bFoundAnyJoysticks
#include "RageLog.h"
#include "RageUtil.h"
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <linux/joystick.h>
#include <set>
REGISTER_INPUT_HANDLER_CLASS2( Joystick, Linux_Joystick );
static const char *Paths[InputHandler_Linux_Joystick::NUM_JOYSTICKS] =
{
"/dev/js0",
"/dev/js1",
"/dev/input/js0",
"/dev/input/js1",
};
InputHandler_Linux_Joystick::InputHandler_Linux_Joystick()
{
LOG->Trace( "InputHandler_Linux_Joystick::InputHandler_Linux_Joystick" );
for(int i = 0; i < NUM_JOYSTICKS; ++i)
fds[i] = -1;
if( InputHandler_Linux_Event::m_bFoundAnyJoysticks )
{
LOG->Trace( "InputHandler_Linux_Joystick disabled (joystick driver already loaded)" );
return;
}
/* We check both eg. /dev/js0 and /dev/input/js0. If both exist, they're probably
* the same device; keep track of device IDs so we don't open the same joystick
* twice. */
set< pair<int,int> > devices;
bool bFoundAnyJoysticks = false;
for(int i = 0; i < NUM_JOYSTICKS; ++i)
{
struct stat st;
if( stat( Paths[i], &st ) == -1 )
{
if( errno != ENOENT )
LOG->Warn( "Couldn't stat %s: %s", Paths[i], strerror(errno) );
continue;
}
if( !S_ISCHR( st.st_mode ) )
{
LOG->Warn( "Ignoring %s: not a character device", Paths[i] );
continue;
}
pair<int,int> dev( major(st.st_rdev), minor(st.st_rdev) );
if( devices.find(dev) != devices.end() )
continue; /* dupe */
devices.insert( dev );
fds[i] = open( Paths[i], O_RDONLY );
if(fds[i] != -1)
{
char szName[1024];
ZERO( szName );
if( ioctl(fds[i], JSIOCGNAME(sizeof(szName)), szName) < 0 )
m_sDescription[i] = ssprintf( "Unknown joystick at %s", Paths[i] );
else
m_sDescription[i] = szName;
LOG->Info("Opened %s", Paths[i]);
bFoundAnyJoysticks = true;
}
}
m_bShutdown = false;
if( bFoundAnyJoysticks )
{
m_InputThread.SetName( "Joystick thread" );
m_InputThread.Create( InputThread_Start, this );
InputHandler_Linux_Event::m_bFoundAnyJoysticks = true;
}
}
InputHandler_Linux_Joystick::~InputHandler_Linux_Joystick()
{
if( m_InputThread.IsCreated() )
{
m_bShutdown = true;
LOG->Trace( "Shutting down joystick thread ..." );
m_InputThread.Wait();
LOG->Trace( "Joystick thread shut down." );
}
for(int i = 0; i < NUM_JOYSTICKS; ++i)
if(fds[i] != -1) close(fds[i]);
}
int InputHandler_Linux_Joystick::InputThread_Start( void *p )
{
((InputHandler_Linux_Joystick *) p)->InputThread();
return 0;
}
void InputHandler_Linux_Joystick::InputThread()
{
while( !m_bShutdown )
{
fd_set fdset;
FD_ZERO(&fdset);
int max_fd = -1;
for(int i = 0; i < NUM_JOYSTICKS; ++i)
{
if (fds[i] < 0)
continue;
FD_SET(fds[i], &fdset);
max_fd = max(max_fd, fds[i]);
}
if(max_fd == -1)
break;
struct timeval zero = {0,100000};
if( select(max_fd+1, &fdset, NULL, NULL, &zero) <= 0 )
continue;
RageTimer now;
printf("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n");
for(int i = 0; i < NUM_JOYSTICKS; ++i)
{
if( fds[i] == -1 )
continue;
if(!FD_ISSET(fds[i], &fdset))
continue;
js_event event;
int ret = read(fds[i], &event, sizeof(event));
if(ret != sizeof(event))
{
LOG->Warn("Unexpected packet (size %i != %i) from joystick %i; disabled", ret, (int)sizeof(event), i);
close(fds[i]);
fds[i] = -1;
continue;
}
InputDevice id = InputDevice(DEVICE_JOY1 + i);
event.type &= ~JS_EVENT_INIT;
switch (event.type) {
case JS_EVENT_BUTTON: {
int iNum = event.number;
// In 2.6.11 using an EMS USB2, the event number for P1 Tri (the first button)
// is being reported as 32 instead of 0. Correct for this.
wrap( iNum, 32 ); // max number of joystick buttons. Make this a constant?
ButtonPressed( DeviceInput(id, enum_add2(JOY_BUTTON_1, iNum), event.value, now) );
break;
}
case JS_EVENT_AXIS: {
DeviceButton neg = enum_add2(JOY_LEFT, 2*event.number);
DeviceButton pos = enum_add2(JOY_RIGHT, 2*event.number);
float l = SCALE( int(event.value), 0.0f, 32767, 0.0f, 1.0f );
ButtonPressed( DeviceInput(id, neg, max(-l,0), now) );
ButtonPressed( DeviceInput(id, pos, max(+l,0), now) );
break;
}
default:
LOG->Warn("Unexpected packet (type %i) from joystick %i; disabled", event.type, i);
close(fds[i]);
fds[i] = -1;
continue;
}
}
}
InputHandler::UpdateTimer();
}
void InputHandler_Linux_Joystick::GetDevicesAndDescriptions( vector<InputDeviceInfo>& vDevicesOut )
{
for(int i = 0; i < NUM_JOYSTICKS; ++i)
{
if (fds[i] < 0)
continue;
vDevicesOut.push_back( InputDeviceInfo(InputDevice(DEVICE_JOY1+i), m_sDescription[i]) );
}
}
/*
* (c) 2003-2004 Glenn Maynard
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, and/or sell copies of the Software, and to permit persons to
* whom the Software is furnished to do so, provided that the above
* copyright notice(s) and this permission notice appear in all copies of
* the Software and that both the above copyright notice(s) and this
* permission notice appear in supporting documentation.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
#include "global.h"
#include "InputHandler_Linux_Joystick.h"
#include "InputHandler_Linux_Event.h" // for m_bFoundAnyJoysticks
#include "RageLog.h"
#include "RageUtil.h"
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <linux/joystick.h>
#include <set>
REGISTER_INPUT_HANDLER_CLASS2( Joystick, Linux_Joystick );
static const char *Paths[InputHandler_Linux_Joystick::NUM_JOYSTICKS] =
{
"/dev/js0",
"/dev/js1",
"/dev/input/js0",
"/dev/input/js1",
};
InputHandler_Linux_Joystick::InputHandler_Linux_Joystick()
{
LOG->Trace( "InputHandler_Linux_Joystick::InputHandler_Linux_Joystick" );
for(int i = 0; i < NUM_JOYSTICKS; ++i)
fds[i] = -1;
if( InputHandler_Linux_Event::m_bFoundAnyJoysticks )
{
LOG->Trace( "InputHandler_Linux_Joystick disabled (joystick driver already loaded)" );
return;
}
/* We check both eg. /dev/js0 and /dev/input/js0. If both exist, they're probably
* the same device; keep track of device IDs so we don't open the same joystick
* twice. */
set< pair<int,int> > devices;
bool bFoundAnyJoysticks = false;
for(int i = 0; i < NUM_JOYSTICKS; ++i)
{
struct stat st;
if( stat( Paths[i], &st ) == -1 )
{
if( errno != ENOENT )
LOG->Warn( "Couldn't stat %s: %s", Paths[i], strerror(errno) );
continue;
}
if( !S_ISCHR( st.st_mode ) )
{
LOG->Warn( "Ignoring %s: not a character device", Paths[i] );
continue;
}
pair<int,int> dev( major(st.st_rdev), minor(st.st_rdev) );
if( devices.find(dev) != devices.end() )
continue; /* dupe */
devices.insert( dev );
fds[i] = open( Paths[i], O_RDONLY );
if(fds[i] != -1)
{
char szName[1024];
ZERO( szName );
if( ioctl(fds[i], JSIOCGNAME(sizeof(szName)), szName) < 0 )
m_sDescription[i] = ssprintf( "Unknown joystick at %s", Paths[i] );
else
m_sDescription[i] = szName;
LOG->Info("Opened %s", Paths[i]);
bFoundAnyJoysticks = true;
}
}
m_bShutdown = false;
if( bFoundAnyJoysticks )
{
m_InputThread.SetName( "Joystick thread" );
m_InputThread.Create( InputThread_Start, this );
InputHandler_Linux_Event::m_bFoundAnyJoysticks = true;
}
}
InputHandler_Linux_Joystick::~InputHandler_Linux_Joystick()
{
if( m_InputThread.IsCreated() )
{
m_bShutdown = true;
LOG->Trace( "Shutting down joystick thread ..." );
m_InputThread.Wait();
LOG->Trace( "Joystick thread shut down." );
}
for(int i = 0; i < NUM_JOYSTICKS; ++i)
if(fds[i] != -1) close(fds[i]);
}
int InputHandler_Linux_Joystick::InputThread_Start( void *p )
{
((InputHandler_Linux_Joystick *) p)->InputThread();
return 0;
}
void InputHandler_Linux_Joystick::InputThread()
{
while( !m_bShutdown )
{
fd_set fdset;
FD_ZERO(&fdset);
int max_fd = -1;
for(int i = 0; i < NUM_JOYSTICKS; ++i)
{
if (fds[i] < 0)
continue;
FD_SET(fds[i], &fdset);
max_fd = max(max_fd, fds[i]);
}
if(max_fd == -1)
break;
struct timeval zero = {0,100000};
if( select(max_fd+1, &fdset, NULL, NULL, &zero) <= 0 )
continue;
RageTimer now;
printf("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n");
for(int i = 0; i < NUM_JOYSTICKS; ++i)
{
if( fds[i] == -1 )
continue;
if(!FD_ISSET(fds[i], &fdset))
continue;
js_event event;
int ret = read(fds[i], &event, sizeof(event));
if(ret != sizeof(event))
{
LOG->Warn("Unexpected packet (size %i != %i) from joystick %i; disabled", ret, (int)sizeof(event), i);
close(fds[i]);
fds[i] = -1;
continue;
}
InputDevice id = InputDevice(DEVICE_JOY1 + i);
event.type &= ~JS_EVENT_INIT;
switch (event.type) {
case JS_EVENT_BUTTON: {
int iNum = event.number;
// In 2.6.11 using an EMS USB2, the event number for P1 Tri (the first button)
// is being reported as 32 instead of 0. Correct for this.
wrap( iNum, 32 ); // max number of joystick buttons. Make this a constant?
ButtonPressed( DeviceInput(id, enum_add2(JOY_BUTTON_1, iNum), event.value, now) );
break;
}
case JS_EVENT_AXIS: {
DeviceButton neg = enum_add2(JOY_LEFT, 2*event.number);
DeviceButton pos = enum_add2(JOY_RIGHT, 2*event.number);
float l = SCALE( int(event.value), 0.0f, 32767, 0.0f, 1.0f );
ButtonPressed( DeviceInput(id, neg, max(-l,0), now) );
ButtonPressed( DeviceInput(id, pos, max(+l,0), now) );
break;
}
default:
LOG->Warn("Unexpected packet (type %i) from joystick %i; disabled", event.type, i);
close(fds[i]);
fds[i] = -1;
continue;
}
}
}
InputHandler::UpdateTimer();
}
void InputHandler_Linux_Joystick::GetDevicesAndDescriptions( vector<InputDeviceInfo>& vDevicesOut )
{
for(int i = 0; i < NUM_JOYSTICKS; ++i)
{
if (fds[i] < 0)
continue;
vDevicesOut.push_back( InputDeviceInfo(InputDevice(DEVICE_JOY1+i), m_sDescription[i]) );
}
}
/*
* (c) 2003-2004 Glenn Maynard
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, and/or sell copies of the Software, and to permit persons to
* whom the Software is furnished to do so, provided that the above
* copyright notice(s) and this permission notice appear in all copies of
* the Software and that both the above copyright notice(s) and this
* permission notice appear in supporting documentation.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
File diff suppressed because it is too large Load Diff
@@ -1,392 +1,392 @@
#include "global.h"
#include "MemoryCardDriverThreaded_Linux.h"
#include "RageLog.h"
#include "RageUtil.h"
#include "RageFile.h"
#include "RageTimer.h"
#include <cerrno>
#include <fcntl.h>
#include <dirent.h>
#include <sys/types.h>
#include <sys/stat.h>
bool MemoryCardDriverThreaded_Linux::TestWrite( UsbStorageDevice* pDevice )
{
if( access(pDevice->sOsMountDir, W_OK) == -1 )
{
pDevice->SetError( "TestFailed" );
return false;
}
return true;
}
static bool ExecuteCommand( const RString &sCommand )
{
LOG->Trace( "executing '%s'", sCommand.c_str() );
int ret = system(sCommand);
LOG->Trace( "done executing '%s'", sCommand.c_str() );
if( ret != 0 )
{
RString sError = ssprintf("failed to execute '%s' with error %d", sCommand.c_str(), ret);
if( ret == -1 )
sError += ssprintf(": %s", sCommand.c_str());
LOG->Warn( "%s", sError.c_str() );
}
return ret == 0;
}
static bool ReadFile( const RString &sPath, RString &sBuf )
{
sBuf.clear();
int fd = open( sPath, O_RDONLY );
if( fd == -1 )
{
LOG->Warn( "Error opening \"%s\": %s", sPath.c_str(), strerror(errno) );
return false;
}
while(1)
{
char buf[1024];
int iGot = read( fd, buf, sizeof(buf) );
if( iGot == -1 )
{
close(fd);
LOG->Warn( "Error reading \"%s\": %s", sPath.c_str(), strerror(errno) );
return false;
}
sBuf.append( buf, iGot );
if( iGot < (int) sizeof(buf) )
break;
}
close(fd);
return true;
}
static void GetFileList( const RString &sPath, vector<RString> &out )
{
out.clear();
DIR *dp = opendir( sPath );
if( dp == NULL )
return; // false; // XXX warn
while( const struct dirent *ent = readdir(dp) )
out.push_back( ent->d_name );
closedir( dp );
}
bool MemoryCardDriverThreaded_Linux::USBStorageDevicesChanged()
{
RString sThisDevices;
/* If a device is removed and reinserted, the inode of the /sys/block entry
* will change. */
RString sDevicePath = "/sys/block/";
vector<RString> asDevices;
GetFileList( sDevicePath, asDevices );
for( unsigned i = 0; i < asDevices.size(); ++i )
{
struct stat buf;
if( stat( sDevicePath + asDevices[i], &buf ) == -1 )
continue; // XXX warn
sThisDevices += ssprintf( "%i,", (int) buf.st_ino );
}
bool bChanged = sThisDevices != m_sLastDevices;
m_sLastDevices = sThisDevices;
if( bChanged )
LOG->Trace( "Change in USB storage devices detected." );
return bChanged;
}
void MemoryCardDriverThreaded_Linux::GetUSBStorageDevices( vector<UsbStorageDevice>& vDevicesOut )
{
LOG->Trace( "GetUSBStorageDevices" );
vDevicesOut.clear();
{
vector<RString> asDevices;
RString sBlockDevicePath = "/sys/block/";
GetFileList( sBlockDevicePath, asDevices );
for( unsigned i = 0; i < asDevices.size(); ++i )
{
const RString &sDevice = asDevices[i];
if( sDevice == "." || sDevice == ".." )
continue;
UsbStorageDevice usbd;
RString sPath = sBlockDevicePath + sDevice + "/";
usbd.sSysPath = sPath;
/* Ignore non-removable devices. */
RString sBuf;
if( !ReadFile( sPath + "removable", sBuf ) )
continue; // already warned
if( atoi(sBuf) != 1 )
continue;
/*
* The kernel isn't exposing all of /sys atomically, so we end up missing
* the partition due to it not being shown yet. It won't show up until the
* kernel has scanned the partition table, which can take a variable amount
* of time, sometimes over a second. Watch for the "queue" sysfs directory,
* which is created after this, to tell when partition directories are created.
*/
RageTimer WaitUntil;
WaitUntil += 5;
RString sQueueFilePath = usbd.sSysPath + "queue";
while(1)
{
if( WaitUntil.Ago() >= 0 )
{
LOG->Warn( "Timed out waiting for %s", sQueueFilePath.c_str() );
break;
}
if( access(usbd.sSysPath, F_OK) == -1 )
{
LOG->Warn( "Block directory %s went away while we were waiting for %s",
usbd.sSysPath.c_str(), sQueueFilePath.c_str() );
break;
}
if( access(sQueueFilePath, F_OK) != -1 )
break;
usleep(10000);
}
/* If the first partition device exists, eg. /sys/block/uba/uba1, use it. */
if( access(usbd.sSysPath + sDevice + "1", F_OK) != -1 )
{
LOG->Trace("OK");
usbd.sDevice = "/dev/" + sDevice + "1";
}
else
{
LOG->Trace("error %s", strerror(errno));
usbd.sDevice = "/dev/" + sDevice;
}
/*
* sPath/device should be a symlink to the actual device. For USB
* devices, it looks like this:
*
* device -> ../../devices/pci0000:00/0000:00:02.1/usb2/2-1/2-1:1.0
*
* "2-1" is "bus-port".
*/
char szLink[256];
int iRet = readlink( sPath + "device", szLink, sizeof(szLink) );
if( iRet == -1 )
{
LOG->Warn( "readlink(\"%s\"): %s", (sPath + "device").c_str(), strerror(errno) );
}
else
{
/*
* The full path looks like
*
* ../../devices/pci0000:00/0000:00:02.1/usb2/2-2/2-2.1/2-2.1:1.0
*
* In newer kernels, it looks like:
*
* ../../../3-2.1:1.0
*
* Each path element refers to a new hop in the chain.
* "usb2" = second USB host
* 2- second USB host,
* -2 port 1 on the host,
* .1 port 1 on an attached hub
* .2 ... port 2 on the next hub ...
*
* We want the bus number and the port of the last hop. The level is
* the number of hops.
*/
szLink[iRet] = 0;
vector<RString> asBits;
split( szLink, "/", asBits );
RString sHostPort = asBits[asBits.size()-1];
if( !sHostPort.empty() )
{
/* Strip off the endpoint information after the colon. */
size_t pos = sHostPort.find(':');
if( pos != string::npos )
sHostPort.erase( pos );
/* sHostPort is eg. 2-2.1. */
sHostPort.Replace( "-", "." );
asBits.clear();
split( sHostPort, ".", asBits );
if( asBits.size() > 1 )
{
usbd.iBus = atoi( asBits[0] );
usbd.iPort = atoi( asBits[asBits.size()-1] );
usbd.iLevel = asBits.size() - 1;
}
}
}
if( ReadFile( sPath + "device/../idVendor", sBuf ) )
sscanf( sBuf, "%x", &usbd.idVendor );
if( ReadFile( sPath + "device/../idProduct", sBuf ) )
sscanf( sBuf, "%x", &usbd.idProduct );
if( ReadFile( sPath + "device/../serial", sBuf ) )
{
usbd.sSerial = sBuf;
TrimRight( usbd.sSerial );
}
if( ReadFile( sPath + "device/../product", sBuf ) )
{
usbd.sProduct = sBuf;
TrimRight( usbd.sProduct );
}
if( ReadFile( sPath + "device/../manufacturer", sBuf ) )
{
usbd.sVendor = sBuf;
TrimRight( usbd.sVendor );
}
vDevicesOut.push_back( usbd );
}
}
{
// Find where each device is mounted. Output looks like:
// /dev/sda1 /mnt/flash1 auto noauto,owner 0 0
// /dev/sdb1 /mnt/flash2 auto noauto,owner 0 0
// /dev/sdc1 /mnt/flash3 auto noauto,owner 0 0
RString fn = "/rootfs/etc/fstab";
RageFile f;
if( !f.Open(fn) )
{
LOG->Warn( "can't open '%s': %s", fn.c_str(), f.GetError().c_str() );
return;
}
RString sLine;
while( !f.AtEOF() )
{
switch( f.GetLine(sLine) )
{
case 0: continue; /* eof */
case -1:
LOG->Warn( "error reading '%s': %s", fn.c_str(), f.GetError().c_str() );
return;
}
char szScsiDevice[1024];
char szMountPoint[1024];
int iRet = sscanf( sLine, "%s %s", szScsiDevice, szMountPoint );
if( iRet != 2 )
continue; // don't process this line
RString sMountPoint = szMountPoint;
TrimLeft( sMountPoint );
TrimRight( sMountPoint );
// search for the mountpoint corresponding to the device
for( unsigned i=0; i<vDevicesOut.size(); i++ )
{
UsbStorageDevice& usbd = vDevicesOut[i];
if( usbd.sDevice == szScsiDevice ) // found our match
{
usbd.sOsMountDir = sMountPoint;
break; // stop looking for a match
}
}
}
}
for( unsigned i=0; i<vDevicesOut.size(); i++ )
{
UsbStorageDevice& usbd = vDevicesOut[i];
LOG->Trace( " sDevice: %s, iBus: %d, iLevel: %d, iPort: %d, id: %04X:%04X, Vendor: '%s', Product: '%s', sSerial: \"%s\", sOsMountDir: %s",
usbd.sDevice.c_str(), usbd.iBus, usbd.iLevel, usbd.iPort, usbd.idVendor, usbd.idProduct, usbd.sVendor.c_str(),
usbd.sProduct.c_str(), usbd.sSerial.c_str(), usbd.sOsMountDir.c_str() );
}
/* Remove any devices that we couldn't find a mountpoint for. */
for( unsigned i=0; i<vDevicesOut.size(); i++ )
{
UsbStorageDevice& usbd = vDevicesOut[i];
if( usbd.sOsMountDir.empty() )
{
LOG->Trace( "Ignoring %s (couldn't find in /etc/fstab)", usbd.sDevice.c_str() );
vDevicesOut.erase( vDevicesOut.begin()+i );
--i;
}
}
LOG->Trace( "Done with GetUSBStorageDevices" );
}
bool MemoryCardDriverThreaded_Linux::Mount( UsbStorageDevice* pDevice )
{
ASSERT( !pDevice->sDevice.empty() );
RString sCommand = "mount " + pDevice->sDevice;
bool bMountedSuccessfully = ExecuteCommand( sCommand );
return bMountedSuccessfully;
}
void MemoryCardDriverThreaded_Linux::Unmount( UsbStorageDevice* pDevice )
{
if( pDevice->sDevice.empty() )
return;
/* Use umount -l, so we unmount the device even if it's in use. Open
* files remain usable, and the device (eg. /dev/sda) won't be reused
* by new devices until those are closed. Without this, if something
* causes the device to not unmount here, we'll never unmount it; that
* causes a device name leak, eventually running us out of mountpoints. */
RString sCommand = "sync; umount -l \"" + pDevice->sDevice + "\"";
ExecuteCommand( sCommand );
}
/*
* (c) 2003-2005 Chris Danford, Glenn Maynard
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, and/or sell copies of the Software, and to permit persons to
* whom the Software is furnished to do so, provided that the above
* copyright notice(s) and this permission notice appear in all copies of
* the Software and that both the above copyright notice(s) and this
* permission notice appear in supporting documentation.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
#include "global.h"
#include "MemoryCardDriverThreaded_Linux.h"
#include "RageLog.h"
#include "RageUtil.h"
#include "RageFile.h"
#include "RageTimer.h"
#include <cerrno>
#include <fcntl.h>
#include <dirent.h>
#include <sys/types.h>
#include <sys/stat.h>
bool MemoryCardDriverThreaded_Linux::TestWrite( UsbStorageDevice* pDevice )
{
if( access(pDevice->sOsMountDir, W_OK) == -1 )
{
pDevice->SetError( "TestFailed" );
return false;
}
return true;
}
static bool ExecuteCommand( const RString &sCommand )
{
LOG->Trace( "executing '%s'", sCommand.c_str() );
int ret = system(sCommand);
LOG->Trace( "done executing '%s'", sCommand.c_str() );
if( ret != 0 )
{
RString sError = ssprintf("failed to execute '%s' with error %d", sCommand.c_str(), ret);
if( ret == -1 )
sError += ssprintf(": %s", sCommand.c_str());
LOG->Warn( "%s", sError.c_str() );
}
return ret == 0;
}
static bool ReadFile( const RString &sPath, RString &sBuf )
{
sBuf.clear();
int fd = open( sPath, O_RDONLY );
if( fd == -1 )
{
LOG->Warn( "Error opening \"%s\": %s", sPath.c_str(), strerror(errno) );
return false;
}
while(1)
{
char buf[1024];
int iGot = read( fd, buf, sizeof(buf) );
if( iGot == -1 )
{
close(fd);
LOG->Warn( "Error reading \"%s\": %s", sPath.c_str(), strerror(errno) );
return false;
}
sBuf.append( buf, iGot );
if( iGot < (int) sizeof(buf) )
break;
}
close(fd);
return true;
}
static void GetFileList( const RString &sPath, vector<RString> &out )
{
out.clear();
DIR *dp = opendir( sPath );
if( dp == NULL )
return; // false; // XXX warn
while( const struct dirent *ent = readdir(dp) )
out.push_back( ent->d_name );
closedir( dp );
}
bool MemoryCardDriverThreaded_Linux::USBStorageDevicesChanged()
{
RString sThisDevices;
/* If a device is removed and reinserted, the inode of the /sys/block entry
* will change. */
RString sDevicePath = "/sys/block/";
vector<RString> asDevices;
GetFileList( sDevicePath, asDevices );
for( unsigned i = 0; i < asDevices.size(); ++i )
{
struct stat buf;
if( stat( sDevicePath + asDevices[i], &buf ) == -1 )
continue; // XXX warn
sThisDevices += ssprintf( "%i,", (int) buf.st_ino );
}
bool bChanged = sThisDevices != m_sLastDevices;
m_sLastDevices = sThisDevices;
if( bChanged )
LOG->Trace( "Change in USB storage devices detected." );
return bChanged;
}
void MemoryCardDriverThreaded_Linux::GetUSBStorageDevices( vector<UsbStorageDevice>& vDevicesOut )
{
LOG->Trace( "GetUSBStorageDevices" );
vDevicesOut.clear();
{
vector<RString> asDevices;
RString sBlockDevicePath = "/sys/block/";
GetFileList( sBlockDevicePath, asDevices );
for( unsigned i = 0; i < asDevices.size(); ++i )
{
const RString &sDevice = asDevices[i];
if( sDevice == "." || sDevice == ".." )
continue;
UsbStorageDevice usbd;
RString sPath = sBlockDevicePath + sDevice + "/";
usbd.sSysPath = sPath;
/* Ignore non-removable devices. */
RString sBuf;
if( !ReadFile( sPath + "removable", sBuf ) )
continue; // already warned
if( atoi(sBuf) != 1 )
continue;
/*
* The kernel isn't exposing all of /sys atomically, so we end up missing
* the partition due to it not being shown yet. It won't show up until the
* kernel has scanned the partition table, which can take a variable amount
* of time, sometimes over a second. Watch for the "queue" sysfs directory,
* which is created after this, to tell when partition directories are created.
*/
RageTimer WaitUntil;
WaitUntil += 5;
RString sQueueFilePath = usbd.sSysPath + "queue";
while(1)
{
if( WaitUntil.Ago() >= 0 )
{
LOG->Warn( "Timed out waiting for %s", sQueueFilePath.c_str() );
break;
}
if( access(usbd.sSysPath, F_OK) == -1 )
{
LOG->Warn( "Block directory %s went away while we were waiting for %s",
usbd.sSysPath.c_str(), sQueueFilePath.c_str() );
break;
}
if( access(sQueueFilePath, F_OK) != -1 )
break;
usleep(10000);
}
/* If the first partition device exists, eg. /sys/block/uba/uba1, use it. */
if( access(usbd.sSysPath + sDevice + "1", F_OK) != -1 )
{
LOG->Trace("OK");
usbd.sDevice = "/dev/" + sDevice + "1";
}
else
{
LOG->Trace("error %s", strerror(errno));
usbd.sDevice = "/dev/" + sDevice;
}
/*
* sPath/device should be a symlink to the actual device. For USB
* devices, it looks like this:
*
* device -> ../../devices/pci0000:00/0000:00:02.1/usb2/2-1/2-1:1.0
*
* "2-1" is "bus-port".
*/
char szLink[256];
int iRet = readlink( sPath + "device", szLink, sizeof(szLink) );
if( iRet == -1 )
{
LOG->Warn( "readlink(\"%s\"): %s", (sPath + "device").c_str(), strerror(errno) );
}
else
{
/*
* The full path looks like
*
* ../../devices/pci0000:00/0000:00:02.1/usb2/2-2/2-2.1/2-2.1:1.0
*
* In newer kernels, it looks like:
*
* ../../../3-2.1:1.0
*
* Each path element refers to a new hop in the chain.
* "usb2" = second USB host
* 2- second USB host,
* -2 port 1 on the host,
* .1 port 1 on an attached hub
* .2 ... port 2 on the next hub ...
*
* We want the bus number and the port of the last hop. The level is
* the number of hops.
*/
szLink[iRet] = 0;
vector<RString> asBits;
split( szLink, "/", asBits );
RString sHostPort = asBits[asBits.size()-1];
if( !sHostPort.empty() )
{
/* Strip off the endpoint information after the colon. */
size_t pos = sHostPort.find(':');
if( pos != string::npos )
sHostPort.erase( pos );
/* sHostPort is eg. 2-2.1. */
sHostPort.Replace( "-", "." );
asBits.clear();
split( sHostPort, ".", asBits );
if( asBits.size() > 1 )
{
usbd.iBus = atoi( asBits[0] );
usbd.iPort = atoi( asBits[asBits.size()-1] );
usbd.iLevel = asBits.size() - 1;
}
}
}
if( ReadFile( sPath + "device/../idVendor", sBuf ) )
sscanf( sBuf, "%x", &usbd.idVendor );
if( ReadFile( sPath + "device/../idProduct", sBuf ) )
sscanf( sBuf, "%x", &usbd.idProduct );
if( ReadFile( sPath + "device/../serial", sBuf ) )
{
usbd.sSerial = sBuf;
TrimRight( usbd.sSerial );
}
if( ReadFile( sPath + "device/../product", sBuf ) )
{
usbd.sProduct = sBuf;
TrimRight( usbd.sProduct );
}
if( ReadFile( sPath + "device/../manufacturer", sBuf ) )
{
usbd.sVendor = sBuf;
TrimRight( usbd.sVendor );
}
vDevicesOut.push_back( usbd );
}
}
{
// Find where each device is mounted. Output looks like:
// /dev/sda1 /mnt/flash1 auto noauto,owner 0 0
// /dev/sdb1 /mnt/flash2 auto noauto,owner 0 0
// /dev/sdc1 /mnt/flash3 auto noauto,owner 0 0
RString fn = "/rootfs/etc/fstab";
RageFile f;
if( !f.Open(fn) )
{
LOG->Warn( "can't open '%s': %s", fn.c_str(), f.GetError().c_str() );
return;
}
RString sLine;
while( !f.AtEOF() )
{
switch( f.GetLine(sLine) )
{
case 0: continue; /* eof */
case -1:
LOG->Warn( "error reading '%s': %s", fn.c_str(), f.GetError().c_str() );
return;
}
char szScsiDevice[1024];
char szMountPoint[1024];
int iRet = sscanf( sLine, "%s %s", szScsiDevice, szMountPoint );
if( iRet != 2 )
continue; // don't process this line
RString sMountPoint = szMountPoint;
TrimLeft( sMountPoint );
TrimRight( sMountPoint );
// search for the mountpoint corresponding to the device
for( unsigned i=0; i<vDevicesOut.size(); i++ )
{
UsbStorageDevice& usbd = vDevicesOut[i];
if( usbd.sDevice == szScsiDevice ) // found our match
{
usbd.sOsMountDir = sMountPoint;
break; // stop looking for a match
}
}
}
}
for( unsigned i=0; i<vDevicesOut.size(); i++ )
{
UsbStorageDevice& usbd = vDevicesOut[i];
LOG->Trace( " sDevice: %s, iBus: %d, iLevel: %d, iPort: %d, id: %04X:%04X, Vendor: '%s', Product: '%s', sSerial: \"%s\", sOsMountDir: %s",
usbd.sDevice.c_str(), usbd.iBus, usbd.iLevel, usbd.iPort, usbd.idVendor, usbd.idProduct, usbd.sVendor.c_str(),
usbd.sProduct.c_str(), usbd.sSerial.c_str(), usbd.sOsMountDir.c_str() );
}
/* Remove any devices that we couldn't find a mountpoint for. */
for( unsigned i=0; i<vDevicesOut.size(); i++ )
{
UsbStorageDevice& usbd = vDevicesOut[i];
if( usbd.sOsMountDir.empty() )
{
LOG->Trace( "Ignoring %s (couldn't find in /etc/fstab)", usbd.sDevice.c_str() );
vDevicesOut.erase( vDevicesOut.begin()+i );
--i;
}
}
LOG->Trace( "Done with GetUSBStorageDevices" );
}
bool MemoryCardDriverThreaded_Linux::Mount( UsbStorageDevice* pDevice )
{
ASSERT( !pDevice->sDevice.empty() );
RString sCommand = "mount " + pDevice->sDevice;
bool bMountedSuccessfully = ExecuteCommand( sCommand );
return bMountedSuccessfully;
}
void MemoryCardDriverThreaded_Linux::Unmount( UsbStorageDevice* pDevice )
{
if( pDevice->sDevice.empty() )
return;
/* Use umount -l, so we unmount the device even if it's in use. Open
* files remain usable, and the device (eg. /dev/sda) won't be reused
* by new devices until those are closed. Without this, if something
* causes the device to not unmount here, we'll never unmount it; that
* causes a device name leak, eventually running us out of mountpoints. */
RString sCommand = "sync; umount -l \"" + pDevice->sDevice + "\"";
ExecuteCommand( sCommand );
}
/*
* (c) 2003-2005 Chris Danford, Glenn Maynard
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, and/or sell copies of the Software, and to permit persons to
* whom the Software is furnished to do so, provided that the above
* copyright notice(s) and this permission notice appear in all copies of
* the Software and that both the above copyright notice(s) and this
* permission notice appear in supporting documentation.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+272 -272
View File
@@ -1,272 +1,272 @@
/*
* unbuffered io for ffmpeg system
* copyright (c) 2001 Fabrice Bellard
*
* This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef AVIO_H
#define AVIO_H
/* output byte stream handling */
typedef int64_t offset_t;
/* unbuffered I/O */
struct URLContext {
struct URLProtocol *prot;
int flags;
int is_streamed; /**< true if streamed (no seek possible), default = false */
int max_packet_size; /**< if non zero, the stream is packetized with this max packet size */
void *priv_data;
#if LIBAVFORMAT_VERSION_INT >= (52<<16)
char *filename; /**< specified filename */
#else
char filename[1]; /**< specified filename */
#endif
};
typedef struct URLContext URLContext;
typedef struct URLPollEntry {
URLContext *handle;
int events;
int revents;
} URLPollEntry;
#define URL_RDONLY 0
#define URL_WRONLY 1
#define URL_RDWR 2
typedef int URLInterruptCB(void);
int url_open(URLContext **h, const char *filename, int flags);
int url_read(URLContext *h, unsigned char *buf, int size);
int url_write(URLContext *h, unsigned char *buf, int size);
offset_t url_seek(URLContext *h, offset_t pos, int whence);
int url_close(URLContext *h);
int url_exist(const char *filename);
offset_t url_filesize(URLContext *h);
/**
* Return the maximum packet size associated to packetized file
* handle. If the file is not packetized (stream like http or file on
* disk), then 0 is returned.
*
* @param h file handle
* @return maximum packet size in bytes
*/
int url_get_max_packet_size(URLContext *h);
void url_get_filename(URLContext *h, char *buf, int buf_size);
/**
* the callback is called in blocking functions to test regulary if
* asynchronous interruption is needed. AVERROR(EINTR) is returned
* in this case by the interrupted function. 'NULL' means no interrupt
* callback is given. i
*/
void url_set_interrupt_cb(URLInterruptCB *interrupt_cb);
/* not implemented */
int url_poll(URLPollEntry *poll_table, int n, int timeout);
/**
* passing this as the "whence" parameter to a seek function causes it to
* return the filesize without seeking anywhere, supporting this is optional
* if its not supprted then the seek function will return <0
*/
#define AVSEEK_SIZE 0x10000
typedef struct URLProtocol {
const char *name;
int (*url_open)(URLContext *h, const char *filename, int flags);
int (*url_read)(URLContext *h, unsigned char *buf, int size);
int (*url_write)(URLContext *h, unsigned char *buf, int size);
offset_t (*url_seek)(URLContext *h, offset_t pos, int whence);
int (*url_close)(URLContext *h);
struct URLProtocol *next;
} URLProtocol;
extern URLProtocol *first_protocol;
extern URLInterruptCB *url_interrupt_cb;
int register_protocol(URLProtocol *protocol);
typedef struct {
unsigned char *buffer;
int buffer_size;
unsigned char *buf_ptr, *buf_end;
void *opaque;
int (*read_packet)(void *opaque, uint8_t *buf, int buf_size);
int (*write_packet)(void *opaque, uint8_t *buf, int buf_size);
offset_t (*seek)(void *opaque, offset_t offset, int whence);
offset_t pos; /**< position in the file of the current buffer */
int must_flush; /**< true if the next seek should flush */
int eof_reached; /**< true if eof reached */
int write_flag; /**< true if open for writing */
int is_streamed;
int max_packet_size;
unsigned long checksum;
unsigned char *checksum_ptr;
unsigned long (*update_checksum)(unsigned long checksum, const uint8_t *buf, unsigned int size);
int error; ///< contains the error code or 0 if no error happened
} ByteIOContext;
int init_put_byte(ByteIOContext *s,
unsigned char *buffer,
int buffer_size,
int write_flag,
void *opaque,
int (*read_packet)(void *opaque, uint8_t *buf, int buf_size),
int (*write_packet)(void *opaque, uint8_t *buf, int buf_size),
offset_t (*seek)(void *opaque, offset_t offset, int whence));
void put_byte(ByteIOContext *s, int b);
void put_buffer(ByteIOContext *s, const unsigned char *buf, int size);
void put_le64(ByteIOContext *s, uint64_t val);
void put_be64(ByteIOContext *s, uint64_t val);
void put_le32(ByteIOContext *s, unsigned int val);
void put_be32(ByteIOContext *s, unsigned int val);
void put_le24(ByteIOContext *s, unsigned int val);
void put_be24(ByteIOContext *s, unsigned int val);
void put_le16(ByteIOContext *s, unsigned int val);
void put_be16(ByteIOContext *s, unsigned int val);
void put_tag(ByteIOContext *s, const char *tag);
void put_strz(ByteIOContext *s, const char *buf);
offset_t url_fseek(ByteIOContext *s, offset_t offset, int whence);
void url_fskip(ByteIOContext *s, offset_t offset);
offset_t url_ftell(ByteIOContext *s);
offset_t url_fsize(ByteIOContext *s);
int url_feof(ByteIOContext *s);
int url_ferror(ByteIOContext *s);
#define URL_EOF (-1)
/** @note return URL_EOF (-1) if EOF */
int url_fgetc(ByteIOContext *s);
/** @warning currently size is limited */
#ifdef __GNUC__
int url_fprintf(ByteIOContext *s, const char *fmt, ...) __attribute__ ((__format__ (__printf__, 2, 3)));
#else
int url_fprintf(ByteIOContext *s, const char *fmt, ...);
#endif
/** @note unlike fgets, the EOL character is not returned and a whole
line is parsed. return NULL if first char read was EOF */
char *url_fgets(ByteIOContext *s, char *buf, int buf_size);
void put_flush_packet(ByteIOContext *s);
int get_buffer(ByteIOContext *s, unsigned char *buf, int size);
int get_partial_buffer(ByteIOContext *s, unsigned char *buf, int size);
/** @note return 0 if EOF, so you cannot use it if EOF handling is
necessary */
int get_byte(ByteIOContext *s);
unsigned int get_le24(ByteIOContext *s);
unsigned int get_le32(ByteIOContext *s);
uint64_t get_le64(ByteIOContext *s);
unsigned int get_le16(ByteIOContext *s);
char *get_strz(ByteIOContext *s, char *buf, int maxlen);
unsigned int get_be16(ByteIOContext *s);
unsigned int get_be24(ByteIOContext *s);
unsigned int get_be32(ByteIOContext *s);
uint64_t get_be64(ByteIOContext *s);
static inline int url_is_streamed(ByteIOContext *s)
{
return s->is_streamed;
}
int url_fdopen(ByteIOContext *s, URLContext *h);
/** @warning must be called before any I/O */
int url_setbufsize(ByteIOContext *s, int buf_size);
/** @note when opened as read/write, the buffers are only used for
reading */
int url_fopen(ByteIOContext *s, const char *filename, int flags);
int url_fclose(ByteIOContext *s);
URLContext *url_fileno(ByteIOContext *s);
/**
* Return the maximum packet size associated to packetized buffered file
* handle. If the file is not packetized (stream like http or file on
* disk), then 0 is returned.
*
* @param h buffered file handle
* @return maximum packet size in bytes
*/
int url_fget_max_packet_size(ByteIOContext *s);
int url_open_buf(ByteIOContext *s, uint8_t *buf, int buf_size, int flags);
/** return the written or read size */
int url_close_buf(ByteIOContext *s);
/**
* Open a write only memory stream.
*
* @param s new IO context
* @return zero if no error.
*/
int url_open_dyn_buf(ByteIOContext *s);
/**
* Open a write only packetized memory stream with a maximum packet
* size of 'max_packet_size'. The stream is stored in a memory buffer
* with a big endian 4 byte header giving the packet size in bytes.
*
* @param s new IO context
* @param max_packet_size maximum packet size (must be > 0)
* @return zero if no error.
*/
int url_open_dyn_packet_buf(ByteIOContext *s, int max_packet_size);
/**
* Return the written size and a pointer to the buffer. The buffer
* must be freed with av_free().
* @param s IO context
* @param pointer to a byte buffer
* @return the length of the byte buffer
*/
int url_close_dyn_buf(ByteIOContext *s, uint8_t **pbuffer);
unsigned long get_checksum(ByteIOContext *s);
void init_checksum(ByteIOContext *s, unsigned long (*update_checksum)(unsigned long c, const uint8_t *p, unsigned int len), unsigned long checksum);
/* file.c */
extern URLProtocol file_protocol;
extern URLProtocol pipe_protocol;
/* udp.c */
extern URLProtocol udp_protocol;
int udp_set_remote_url(URLContext *h, const char *uri);
int udp_get_local_port(URLContext *h);
int udp_get_file_handle(URLContext *h);
/* tcp.c */
extern URLProtocol tcp_protocol;
/* http.c */
extern URLProtocol http_protocol;
#endif
/*
* unbuffered io for ffmpeg system
* copyright (c) 2001 Fabrice Bellard
*
* This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef AVIO_H
#define AVIO_H
/* output byte stream handling */
typedef int64_t offset_t;
/* unbuffered I/O */
struct URLContext {
struct URLProtocol *prot;
int flags;
int is_streamed; /**< true if streamed (no seek possible), default = false */
int max_packet_size; /**< if non zero, the stream is packetized with this max packet size */
void *priv_data;
#if LIBAVFORMAT_VERSION_INT >= (52<<16)
char *filename; /**< specified filename */
#else
char filename[1]; /**< specified filename */
#endif
};
typedef struct URLContext URLContext;
typedef struct URLPollEntry {
URLContext *handle;
int events;
int revents;
} URLPollEntry;
#define URL_RDONLY 0
#define URL_WRONLY 1
#define URL_RDWR 2
typedef int URLInterruptCB(void);
int url_open(URLContext **h, const char *filename, int flags);
int url_read(URLContext *h, unsigned char *buf, int size);
int url_write(URLContext *h, unsigned char *buf, int size);
offset_t url_seek(URLContext *h, offset_t pos, int whence);
int url_close(URLContext *h);
int url_exist(const char *filename);
offset_t url_filesize(URLContext *h);
/**
* Return the maximum packet size associated to packetized file
* handle. If the file is not packetized (stream like http or file on
* disk), then 0 is returned.
*
* @param h file handle
* @return maximum packet size in bytes
*/
int url_get_max_packet_size(URLContext *h);
void url_get_filename(URLContext *h, char *buf, int buf_size);
/**
* the callback is called in blocking functions to test regulary if
* asynchronous interruption is needed. AVERROR(EINTR) is returned
* in this case by the interrupted function. 'NULL' means no interrupt
* callback is given. i
*/
void url_set_interrupt_cb(URLInterruptCB *interrupt_cb);
/* not implemented */
int url_poll(URLPollEntry *poll_table, int n, int timeout);
/**
* passing this as the "whence" parameter to a seek function causes it to
* return the filesize without seeking anywhere, supporting this is optional
* if its not supprted then the seek function will return <0
*/
#define AVSEEK_SIZE 0x10000
typedef struct URLProtocol {
const char *name;
int (*url_open)(URLContext *h, const char *filename, int flags);
int (*url_read)(URLContext *h, unsigned char *buf, int size);
int (*url_write)(URLContext *h, unsigned char *buf, int size);
offset_t (*url_seek)(URLContext *h, offset_t pos, int whence);
int (*url_close)(URLContext *h);
struct URLProtocol *next;
} URLProtocol;
extern URLProtocol *first_protocol;
extern URLInterruptCB *url_interrupt_cb;
int register_protocol(URLProtocol *protocol);
typedef struct {
unsigned char *buffer;
int buffer_size;
unsigned char *buf_ptr, *buf_end;
void *opaque;
int (*read_packet)(void *opaque, uint8_t *buf, int buf_size);
int (*write_packet)(void *opaque, uint8_t *buf, int buf_size);
offset_t (*seek)(void *opaque, offset_t offset, int whence);
offset_t pos; /**< position in the file of the current buffer */
int must_flush; /**< true if the next seek should flush */
int eof_reached; /**< true if eof reached */
int write_flag; /**< true if open for writing */
int is_streamed;
int max_packet_size;
unsigned long checksum;
unsigned char *checksum_ptr;
unsigned long (*update_checksum)(unsigned long checksum, const uint8_t *buf, unsigned int size);
int error; ///< contains the error code or 0 if no error happened
} ByteIOContext;
int init_put_byte(ByteIOContext *s,
unsigned char *buffer,
int buffer_size,
int write_flag,
void *opaque,
int (*read_packet)(void *opaque, uint8_t *buf, int buf_size),
int (*write_packet)(void *opaque, uint8_t *buf, int buf_size),
offset_t (*seek)(void *opaque, offset_t offset, int whence));
void put_byte(ByteIOContext *s, int b);
void put_buffer(ByteIOContext *s, const unsigned char *buf, int size);
void put_le64(ByteIOContext *s, uint64_t val);
void put_be64(ByteIOContext *s, uint64_t val);
void put_le32(ByteIOContext *s, unsigned int val);
void put_be32(ByteIOContext *s, unsigned int val);
void put_le24(ByteIOContext *s, unsigned int val);
void put_be24(ByteIOContext *s, unsigned int val);
void put_le16(ByteIOContext *s, unsigned int val);
void put_be16(ByteIOContext *s, unsigned int val);
void put_tag(ByteIOContext *s, const char *tag);
void put_strz(ByteIOContext *s, const char *buf);
offset_t url_fseek(ByteIOContext *s, offset_t offset, int whence);
void url_fskip(ByteIOContext *s, offset_t offset);
offset_t url_ftell(ByteIOContext *s);
offset_t url_fsize(ByteIOContext *s);
int url_feof(ByteIOContext *s);
int url_ferror(ByteIOContext *s);
#define URL_EOF (-1)
/** @note return URL_EOF (-1) if EOF */
int url_fgetc(ByteIOContext *s);
/** @warning currently size is limited */
#ifdef __GNUC__
int url_fprintf(ByteIOContext *s, const char *fmt, ...) __attribute__ ((__format__ (__printf__, 2, 3)));
#else
int url_fprintf(ByteIOContext *s, const char *fmt, ...);
#endif
/** @note unlike fgets, the EOL character is not returned and a whole
line is parsed. return NULL if first char read was EOF */
char *url_fgets(ByteIOContext *s, char *buf, int buf_size);
void put_flush_packet(ByteIOContext *s);
int get_buffer(ByteIOContext *s, unsigned char *buf, int size);
int get_partial_buffer(ByteIOContext *s, unsigned char *buf, int size);
/** @note return 0 if EOF, so you cannot use it if EOF handling is
necessary */
int get_byte(ByteIOContext *s);
unsigned int get_le24(ByteIOContext *s);
unsigned int get_le32(ByteIOContext *s);
uint64_t get_le64(ByteIOContext *s);
unsigned int get_le16(ByteIOContext *s);
char *get_strz(ByteIOContext *s, char *buf, int maxlen);
unsigned int get_be16(ByteIOContext *s);
unsigned int get_be24(ByteIOContext *s);
unsigned int get_be32(ByteIOContext *s);
uint64_t get_be64(ByteIOContext *s);
static inline int url_is_streamed(ByteIOContext *s)
{
return s->is_streamed;
}
int url_fdopen(ByteIOContext *s, URLContext *h);
/** @warning must be called before any I/O */
int url_setbufsize(ByteIOContext *s, int buf_size);
/** @note when opened as read/write, the buffers are only used for
reading */
int url_fopen(ByteIOContext *s, const char *filename, int flags);
int url_fclose(ByteIOContext *s);
URLContext *url_fileno(ByteIOContext *s);
/**
* Return the maximum packet size associated to packetized buffered file
* handle. If the file is not packetized (stream like http or file on
* disk), then 0 is returned.
*
* @param h buffered file handle
* @return maximum packet size in bytes
*/
int url_fget_max_packet_size(ByteIOContext *s);
int url_open_buf(ByteIOContext *s, uint8_t *buf, int buf_size, int flags);
/** return the written or read size */
int url_close_buf(ByteIOContext *s);
/**
* Open a write only memory stream.
*
* @param s new IO context
* @return zero if no error.
*/
int url_open_dyn_buf(ByteIOContext *s);
/**
* Open a write only packetized memory stream with a maximum packet
* size of 'max_packet_size'. The stream is stored in a memory buffer
* with a big endian 4 byte header giving the packet size in bytes.
*
* @param s new IO context
* @param max_packet_size maximum packet size (must be > 0)
* @return zero if no error.
*/
int url_open_dyn_packet_buf(ByteIOContext *s, int max_packet_size);
/**
* Return the written size and a pointer to the buffer. The buffer
* must be freed with av_free().
* @param s IO context
* @param pointer to a byte buffer
* @return the length of the byte buffer
*/
int url_close_dyn_buf(ByteIOContext *s, uint8_t **pbuffer);
unsigned long get_checksum(ByteIOContext *s);
void init_checksum(ByteIOContext *s, unsigned long (*update_checksum)(unsigned long c, const uint8_t *p, unsigned int len), unsigned long checksum);
/* file.c */
extern URLProtocol file_protocol;
extern URLProtocol pipe_protocol;
/* udp.c */
extern URLProtocol udp_protocol;
int udp_set_remote_url(URLContext *h, const char *uri);
int udp_get_local_port(URLContext *h);
int udp_get_file_handle(URLContext *h);
/* tcp.c */
extern URLProtocol tcp_protocol;
/* http.c */
extern URLProtocol http_protocol;
#endif
+137 -137
View File
@@ -1,137 +1,137 @@
/*
* copyright (c) 2006 Michael Niedermayer <[email protected]>
*
* This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef AVUTIL_H
#define AVUTIL_H
/**
* @file avutil.h
* external api header.
*/
#ifdef __cplusplus
extern "C" {
#endif
#define AV_STRINGIFY(s) AV_TOSTRING(s)
#define AV_TOSTRING(s) #s
#define LIBAVUTIL_VERSION_INT ((49<<16)+(4<<8)+0)
#define LIBAVUTIL_VERSION 49.4.0
#define LIBAVUTIL_BUILD LIBAVUTIL_VERSION_INT
#define LIBAVUTIL_IDENT "Lavu" AV_STRINGIFY(LIBAVUTIL_VERSION)
#include "common.h"
#include "mathematics.h"
#include "rational.h"
#include "integer.h"
#include "intfloat_readwrite.h"
#include "log.h"
/**
* Pixel format. Notes:
*
* PIX_FMT_RGB32 is handled in an endian-specific manner. A RGBA
* color is put together as:
* (A << 24) | (R << 16) | (G << 8) | B
* This is stored as BGRA on little endian CPU architectures and ARGB on
* big endian CPUs.
*
* When the pixel format is palettized RGB (PIX_FMT_PAL8), the palettized
* image data is stored in AVFrame.data[0]. The palette is transported in
* AVFrame.data[1] and, is 1024 bytes long (256 4-byte entries) and is
* formatted the same as in PIX_FMT_RGB32 described above (i.e., it is
* also endian-specific). Note also that the individual RGB palette
* components stored in AVFrame.data[1] should be in the range 0..255.
* This is important as many custom PAL8 video codecs that were designed
* to run on the IBM VGA graphics adapter use 6-bit palette components.
*/
enum PixelFormat {
PIX_FMT_NONE= -1,
PIX_FMT_YUV420P, ///< Planar YUV 4:2:0, 12bpp, (1 Cr & Cb sample per 2x2 Y samples)
PIX_FMT_YUYV422, ///< Packed YUV 4:2:2, 16bpp, Y0 Cb Y1 Cr
PIX_FMT_RGB24, ///< Packed RGB 8:8:8, 24bpp, RGBRGB...
PIX_FMT_BGR24, ///< Packed RGB 8:8:8, 24bpp, BGRBGR...
PIX_FMT_YUV422P, ///< Planar YUV 4:2:2, 16bpp, (1 Cr & Cb sample per 2x1 Y samples)
PIX_FMT_YUV444P, ///< Planar YUV 4:4:4, 24bpp, (1 Cr & Cb sample per 1x1 Y samples)
PIX_FMT_RGB32, ///< Packed RGB 8:8:8, 32bpp, (msb)8A 8R 8G 8B(lsb), in cpu endianness
PIX_FMT_YUV410P, ///< Planar YUV 4:1:0, 9bpp, (1 Cr & Cb sample per 4x4 Y samples)
PIX_FMT_YUV411P, ///< Planar YUV 4:1:1, 12bpp, (1 Cr & Cb sample per 4x1 Y samples)
PIX_FMT_RGB565, ///< Packed RGB 5:6:5, 16bpp, (msb) 5R 6G 5B(lsb), in cpu endianness
PIX_FMT_RGB555, ///< Packed RGB 5:5:5, 16bpp, (msb)1A 5R 5G 5B(lsb), in cpu endianness most significant bit to 0
PIX_FMT_GRAY8, ///< Y , 8bpp
PIX_FMT_MONOWHITE, ///< Y , 1bpp, 1 is white
PIX_FMT_MONOBLACK, ///< Y , 1bpp, 0 is black
PIX_FMT_PAL8, ///< 8 bit with PIX_FMT_RGB32 palette
PIX_FMT_YUVJ420P, ///< Planar YUV 4:2:0, 12bpp, full scale (jpeg)
PIX_FMT_YUVJ422P, ///< Planar YUV 4:2:2, 16bpp, full scale (jpeg)
PIX_FMT_YUVJ444P, ///< Planar YUV 4:4:4, 24bpp, full scale (jpeg)
PIX_FMT_XVMC_MPEG2_MC,///< XVideo Motion Acceleration via common packet passing(xvmc_render.h)
PIX_FMT_XVMC_MPEG2_IDCT,
PIX_FMT_UYVY422, ///< Packed YUV 4:2:2, 16bpp, Cb Y0 Cr Y1
PIX_FMT_UYYVYY411, ///< Packed YUV 4:1:1, 12bpp, Cb Y0 Y1 Cr Y2 Y3
PIX_FMT_BGR32, ///< Packed RGB 8:8:8, 32bpp, (msb)8A 8B 8G 8R(lsb), in cpu endianness
PIX_FMT_BGR565, ///< Packed RGB 5:6:5, 16bpp, (msb) 5B 6G 5R(lsb), in cpu endianness
PIX_FMT_BGR555, ///< Packed RGB 5:5:5, 16bpp, (msb)1A 5B 5G 5R(lsb), in cpu endianness most significant bit to 1
PIX_FMT_BGR8, ///< Packed RGB 3:3:2, 8bpp, (msb)2B 3G 3R(lsb)
PIX_FMT_BGR4, ///< Packed RGB 1:2:1, 4bpp, (msb)1B 2G 1R(lsb)
PIX_FMT_BGR4_BYTE, ///< Packed RGB 1:2:1, 8bpp, (msb)1B 2G 1R(lsb)
PIX_FMT_RGB8, ///< Packed RGB 3:3:2, 8bpp, (msb)2R 3G 3B(lsb)
PIX_FMT_RGB4, ///< Packed RGB 1:2:1, 4bpp, (msb)2R 3G 3B(lsb)
PIX_FMT_RGB4_BYTE, ///< Packed RGB 1:2:1, 8bpp, (msb)2R 3G 3B(lsb)
PIX_FMT_NV12, ///< Planar YUV 4:2:0, 12bpp, 1 plane for Y and 1 for UV
PIX_FMT_NV21, ///< as above, but U and V bytes are swapped
PIX_FMT_RGB32_1, ///< Packed RGB 8:8:8, 32bpp, (msb)8R 8G 8B 8A(lsb), in cpu endianness
PIX_FMT_BGR32_1, ///< Packed RGB 8:8:8, 32bpp, (msb)8B 8G 8R 8A(lsb), in cpu endianness
PIX_FMT_GRAY16BE, ///< Y , 16bpp, big-endian
PIX_FMT_GRAY16LE, ///< Y , 16bpp, little-endian
PIX_FMT_NB, ///< number of pixel formats, DO NOT USE THIS if you want to link with shared libav* because the number of formats might differ between versions
};
#ifdef WORDS_BIGENDIAN
#define PIX_FMT_RGBA PIX_FMT_RGB32_1
#define PIX_FMT_BGRA PIX_FMT_BGR32_1
#define PIX_FMT_ARGB PIX_FMT_RGB32
#define PIX_FMT_ABGR PIX_FMT_BGR32
#define PIX_FMT_GRAY16 PIX_FMT_GRAY16BE
#else
#define PIX_FMT_RGBA PIX_FMT_BGR32
#define PIX_FMT_BGRA PIX_FMT_RGB32
#define PIX_FMT_ARGB PIX_FMT_BGR32_1
#define PIX_FMT_ABGR PIX_FMT_RGB32_1
#define PIX_FMT_GRAY16 PIX_FMT_GRAY16LE
#endif
#if LIBAVUTIL_VERSION_INT < (50<<16)
#define PIX_FMT_UYVY411 PIX_FMT_UYYVYY411
#define PIX_FMT_RGBA32 PIX_FMT_RGB32
#define PIX_FMT_YUV422 PIX_FMT_YUYV422
#endif
#ifdef __cplusplus
}
#endif
#endif /* AVUTIL_H */
/*
* copyright (c) 2006 Michael Niedermayer <[email protected]>
*
* This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef AVUTIL_H
#define AVUTIL_H
/**
* @file avutil.h
* external api header.
*/
#ifdef __cplusplus
extern "C" {
#endif
#define AV_STRINGIFY(s) AV_TOSTRING(s)
#define AV_TOSTRING(s) #s
#define LIBAVUTIL_VERSION_INT ((49<<16)+(4<<8)+0)
#define LIBAVUTIL_VERSION 49.4.0
#define LIBAVUTIL_BUILD LIBAVUTIL_VERSION_INT
#define LIBAVUTIL_IDENT "Lavu" AV_STRINGIFY(LIBAVUTIL_VERSION)
#include "common.h"
#include "mathematics.h"
#include "rational.h"
#include "integer.h"
#include "intfloat_readwrite.h"
#include "log.h"
/**
* Pixel format. Notes:
*
* PIX_FMT_RGB32 is handled in an endian-specific manner. A RGBA
* color is put together as:
* (A << 24) | (R << 16) | (G << 8) | B
* This is stored as BGRA on little endian CPU architectures and ARGB on
* big endian CPUs.
*
* When the pixel format is palettized RGB (PIX_FMT_PAL8), the palettized
* image data is stored in AVFrame.data[0]. The palette is transported in
* AVFrame.data[1] and, is 1024 bytes long (256 4-byte entries) and is
* formatted the same as in PIX_FMT_RGB32 described above (i.e., it is
* also endian-specific). Note also that the individual RGB palette
* components stored in AVFrame.data[1] should be in the range 0..255.
* This is important as many custom PAL8 video codecs that were designed
* to run on the IBM VGA graphics adapter use 6-bit palette components.
*/
enum PixelFormat {
PIX_FMT_NONE= -1,
PIX_FMT_YUV420P, ///< Planar YUV 4:2:0, 12bpp, (1 Cr & Cb sample per 2x2 Y samples)
PIX_FMT_YUYV422, ///< Packed YUV 4:2:2, 16bpp, Y0 Cb Y1 Cr
PIX_FMT_RGB24, ///< Packed RGB 8:8:8, 24bpp, RGBRGB...
PIX_FMT_BGR24, ///< Packed RGB 8:8:8, 24bpp, BGRBGR...
PIX_FMT_YUV422P, ///< Planar YUV 4:2:2, 16bpp, (1 Cr & Cb sample per 2x1 Y samples)
PIX_FMT_YUV444P, ///< Planar YUV 4:4:4, 24bpp, (1 Cr & Cb sample per 1x1 Y samples)
PIX_FMT_RGB32, ///< Packed RGB 8:8:8, 32bpp, (msb)8A 8R 8G 8B(lsb), in cpu endianness
PIX_FMT_YUV410P, ///< Planar YUV 4:1:0, 9bpp, (1 Cr & Cb sample per 4x4 Y samples)
PIX_FMT_YUV411P, ///< Planar YUV 4:1:1, 12bpp, (1 Cr & Cb sample per 4x1 Y samples)
PIX_FMT_RGB565, ///< Packed RGB 5:6:5, 16bpp, (msb) 5R 6G 5B(lsb), in cpu endianness
PIX_FMT_RGB555, ///< Packed RGB 5:5:5, 16bpp, (msb)1A 5R 5G 5B(lsb), in cpu endianness most significant bit to 0
PIX_FMT_GRAY8, ///< Y , 8bpp
PIX_FMT_MONOWHITE, ///< Y , 1bpp, 1 is white
PIX_FMT_MONOBLACK, ///< Y , 1bpp, 0 is black
PIX_FMT_PAL8, ///< 8 bit with PIX_FMT_RGB32 palette
PIX_FMT_YUVJ420P, ///< Planar YUV 4:2:0, 12bpp, full scale (jpeg)
PIX_FMT_YUVJ422P, ///< Planar YUV 4:2:2, 16bpp, full scale (jpeg)
PIX_FMT_YUVJ444P, ///< Planar YUV 4:4:4, 24bpp, full scale (jpeg)
PIX_FMT_XVMC_MPEG2_MC,///< XVideo Motion Acceleration via common packet passing(xvmc_render.h)
PIX_FMT_XVMC_MPEG2_IDCT,
PIX_FMT_UYVY422, ///< Packed YUV 4:2:2, 16bpp, Cb Y0 Cr Y1
PIX_FMT_UYYVYY411, ///< Packed YUV 4:1:1, 12bpp, Cb Y0 Y1 Cr Y2 Y3
PIX_FMT_BGR32, ///< Packed RGB 8:8:8, 32bpp, (msb)8A 8B 8G 8R(lsb), in cpu endianness
PIX_FMT_BGR565, ///< Packed RGB 5:6:5, 16bpp, (msb) 5B 6G 5R(lsb), in cpu endianness
PIX_FMT_BGR555, ///< Packed RGB 5:5:5, 16bpp, (msb)1A 5B 5G 5R(lsb), in cpu endianness most significant bit to 1
PIX_FMT_BGR8, ///< Packed RGB 3:3:2, 8bpp, (msb)2B 3G 3R(lsb)
PIX_FMT_BGR4, ///< Packed RGB 1:2:1, 4bpp, (msb)1B 2G 1R(lsb)
PIX_FMT_BGR4_BYTE, ///< Packed RGB 1:2:1, 8bpp, (msb)1B 2G 1R(lsb)
PIX_FMT_RGB8, ///< Packed RGB 3:3:2, 8bpp, (msb)2R 3G 3B(lsb)
PIX_FMT_RGB4, ///< Packed RGB 1:2:1, 4bpp, (msb)2R 3G 3B(lsb)
PIX_FMT_RGB4_BYTE, ///< Packed RGB 1:2:1, 8bpp, (msb)2R 3G 3B(lsb)
PIX_FMT_NV12, ///< Planar YUV 4:2:0, 12bpp, 1 plane for Y and 1 for UV
PIX_FMT_NV21, ///< as above, but U and V bytes are swapped
PIX_FMT_RGB32_1, ///< Packed RGB 8:8:8, 32bpp, (msb)8R 8G 8B 8A(lsb), in cpu endianness
PIX_FMT_BGR32_1, ///< Packed RGB 8:8:8, 32bpp, (msb)8B 8G 8R 8A(lsb), in cpu endianness
PIX_FMT_GRAY16BE, ///< Y , 16bpp, big-endian
PIX_FMT_GRAY16LE, ///< Y , 16bpp, little-endian
PIX_FMT_NB, ///< number of pixel formats, DO NOT USE THIS if you want to link with shared libav* because the number of formats might differ between versions
};
#ifdef WORDS_BIGENDIAN
#define PIX_FMT_RGBA PIX_FMT_RGB32_1
#define PIX_FMT_BGRA PIX_FMT_BGR32_1
#define PIX_FMT_ARGB PIX_FMT_RGB32
#define PIX_FMT_ABGR PIX_FMT_BGR32
#define PIX_FMT_GRAY16 PIX_FMT_GRAY16BE
#else
#define PIX_FMT_RGBA PIX_FMT_BGR32
#define PIX_FMT_BGRA PIX_FMT_RGB32
#define PIX_FMT_ARGB PIX_FMT_BGR32_1
#define PIX_FMT_ABGR PIX_FMT_RGB32_1
#define PIX_FMT_GRAY16 PIX_FMT_GRAY16LE
#endif
#if LIBAVUTIL_VERSION_INT < (50<<16)
#define PIX_FMT_UYVY411 PIX_FMT_UYYVYY411
#define PIX_FMT_RGBA32 PIX_FMT_RGB32
#define PIX_FMT_YUV422 PIX_FMT_YUYV422
#endif
#ifdef __cplusplus
}
#endif
#endif /* AVUTIL_H */
+328 -328
View File
@@ -1,328 +1,328 @@
/*
* copyright (c) 2006 Michael Niedermayer <[email protected]>
*
* This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/**
* @file common.h
* common internal and external api header.
*/
#ifndef COMMON_H
#define COMMON_H
#if 0
#include <inttypes.h>
#endif
#ifdef HAVE_AV_CONFIG_H
/* only include the following when compiling package */
# include "config.h"
# include <stdlib.h>
# include <stdio.h>
# include <string.h>
# include <ctype.h>
# include <limits.h>
# include <errno.h>
# include <math.h>
#endif /* HAVE_AV_CONFIG_H */
#ifndef av_always_inline
#if defined(__GNUC__) && (__GNUC__ > 3 || __GNUC__ == 3 && __GNUC_MINOR__ > 0)
# define av_always_inline __attribute__((always_inline)) inline
# define av_noinline __attribute__((noinline))
#else
# define av_always_inline inline
# define av_noinline
#endif
#endif
#ifdef HAVE_AV_CONFIG_H
# include "internal.h"
#endif /* HAVE_AV_CONFIG_H */
#ifndef attribute_deprecated
#if defined(__GNUC__) && (__GNUC__ > 3 || __GNUC__ == 3 && __GNUC_MINOR__ > 0)
# define attribute_deprecated __attribute__((deprecated))
#else
# define attribute_deprecated
#endif
#endif
#include "mem.h"
//rounded divison & shift
#define RSHIFT(a,b) ((a) > 0 ? ((a) + ((1<<(b))>>1))>>(b) : ((a) + ((1<<(b))>>1)-1)>>(b))
/* assume b>0 */
#define ROUNDED_DIV(a,b) (((a)>0 ? (a) + ((b)>>1) : (a) - ((b)>>1))/(b))
#define FFABS(a) ((a) >= 0 ? (a) : (-(a)))
#define FFSIGN(a) ((a) > 0 ? 1 : -1)
#define FFMAX(a,b) ((a) > (b) ? (a) : (b))
#define FFMIN(a,b) ((a) > (b) ? (b) : (a))
#define FFSWAP(type,a,b) do{type SWAP_tmp= b; b= a; a= SWAP_tmp;}while(0)
/* misc math functions */
extern const uint8_t ff_log2_tab[256];
static inline int av_log2(unsigned int v)
{
int n;
n = 0;
if (v & 0xffff0000) {
v >>= 16;
n += 16;
}
if (v & 0xff00) {
v >>= 8;
n += 8;
}
n += ff_log2_tab[v];
return n;
}
static inline int av_log2_16bit(unsigned int v)
{
int n;
n = 0;
if (v & 0xff00) {
v >>= 8;
n += 8;
}
n += ff_log2_tab[v];
return n;
}
/* median of 3 */
static inline int mid_pred(int a, int b, int c)
{
#ifdef HAVE_CMOV
int i=b;
asm volatile(
"cmp %2, %1 \n\t"
"cmovg %1, %0 \n\t"
"cmovg %2, %1 \n\t"
"cmp %3, %1 \n\t"
"cmovl %3, %1 \n\t"
"cmp %1, %0 \n\t"
"cmovg %1, %0 \n\t"
:"+&r"(i), "+&r"(a)
:"r"(b), "r"(c)
);
return i;
#elif 0
int t= (a-b)&((a-b)>>31);
a-=t;
b+=t;
b-= (b-c)&((b-c)>>31);
b+= (a-b)&((a-b)>>31);
return b;
#else
if(a>b){
if(c>b){
if(c>a) b=a;
else b=c;
}
}else{
if(b>c){
if(c>a) b=c;
else b=a;
}
}
return b;
#endif
}
/**
* clip a signed integer value into the amin-amax range
* @param a value to clip
* @param amin minimum value of the clip range
* @param amax maximum value of the clip range
* @return clipped value
*/
static inline int av_clip(int a, int amin, int amax)
{
if (a < amin) return amin;
else if (a > amax) return amax;
else return a;
}
/**
* clip a signed integer value into the 0-255 range
* @param a value to clip
* @return clipped value
*/
static inline uint8_t av_clip_uint8(int a)
{
if (a&(~255)) return (-a)>>31;
else return a;
}
/* math */
int64_t ff_gcd(int64_t a, int64_t b);
/**
* converts fourcc string to int
*/
static inline int ff_get_fourcc(const char *s){
#ifdef HAVE_AV_CONFIG_H
assert( strlen(s)==4 );
#endif
return (s[0]) + (s[1]<<8) + (s[2]<<16) + (s[3]<<24);
}
#define MKTAG(a,b,c,d) (a | (b << 8) | (c << 16) | (d << 24))
#define MKBETAG(a,b,c,d) (d | (c << 8) | (b << 16) | (a << 24))
/*!
* \def GET_UTF8(val, GET_BYTE, ERROR)
* converts a utf-8 character (up to 4 bytes long) to its 32-bit ucs-4 encoded form
* \param val is the output and should be of type uint32_t. It holds the converted
* ucs-4 character and should be a left value.
* \param GET_BYTE gets utf-8 encoded bytes from any proper source. It can be
* a function or a statement whose return value or evaluated value is of type
* uint8_t. It will be executed up to 4 times for values in the valid utf-8 range,
* and up to 7 times in the general case.
* \param ERROR action that should be taken when an invalid utf-8 byte is returned
* from GET_BYTE. It should be a statement that jumps out of the macro,
* like exit(), goto, return, break, or continue.
*/
#define GET_UTF8(val, GET_BYTE, ERROR)\
val= GET_BYTE;\
{\
int ones= 7 - av_log2(val ^ 255);\
if(ones==1)\
ERROR\
val&= 127>>ones;\
while(--ones > 0){\
int tmp= GET_BYTE - 128;\
if(tmp>>6)\
ERROR\
val= (val<<6) + tmp;\
}\
}
/*!
* \def PUT_UTF8(val, tmp, PUT_BYTE)
* converts a 32-bit unicode character to its utf-8 encoded form (up to 4 bytes long).
* \param val is an input only argument and should be of type uint32_t. It holds
* a ucs4 encoded unicode character that is to be converted to utf-8. If
* val is given as a function it's executed only once.
* \param tmp is a temporary variable and should be of type uint8_t. It
* represents an intermediate value during conversion that is to be
* outputted by PUT_BYTE.
* \param PUT_BYTE writes the converted utf-8 bytes to any proper destination.
* It could be a function or a statement, and uses tmp as the input byte.
* For example, PUT_BYTE could be "*output++ = tmp;" PUT_BYTE will be
* executed up to 4 times for values in the valid utf-8 range and up to
* 7 times in the general case, depending on the length of the converted
* unicode character.
*/
#define PUT_UTF8(val, tmp, PUT_BYTE)\
{\
int bytes, shift;\
uint32_t in = val;\
if (in < 0x80) {\
tmp = in;\
PUT_BYTE\
} else {\
bytes = (av_log2(in) + 4) / 5;\
shift = (bytes - 1) * 6;\
tmp = (256 - (256 >> bytes)) | (in >> shift);\
PUT_BYTE\
while (shift >= 6) {\
shift -= 6;\
tmp = 0x80 | ((in >> shift) & 0x3f);\
PUT_BYTE\
}\
}\
}
#if defined(ARCH_X86) || defined(ARCH_POWERPC)
#if defined(ARCH_X86_64)
static inline uint64_t read_time(void)
{
uint64_t a, d;
asm volatile( "rdtsc\n\t"
: "=a" (a), "=d" (d)
);
return (d << 32) | (a & 0xffffffff);
}
#elif defined(ARCH_X86_32)
static inline long long read_time(void)
{
long long l;
asm volatile( "rdtsc\n\t"
: "=A" (l)
);
return l;
}
#else //FIXME check ppc64
static inline uint64_t read_time(void)
{
uint32_t tbu, tbl, temp;
/* from section 2.2.1 of the 32-bit PowerPC PEM */
__asm__ __volatile__(
"1:\n"
"mftbu %2\n"
"mftb %0\n"
"mftbu %1\n"
"cmpw %2,%1\n"
"bne 1b\n"
: "=r"(tbl), "=r"(tbu), "=r"(temp)
:
: "cc");
return (((uint64_t)tbu)<<32) | (uint64_t)tbl;
}
#endif
#define START_TIMER \
uint64_t tend;\
uint64_t tstart= read_time();\
#define STOP_TIMER(id) \
tend= read_time();\
{\
static uint64_t tsum=0;\
static int tcount=0;\
static int tskip_count=0;\
if(tcount<2 || tend - tstart < FFMAX(8*tsum/tcount, 2000)){\
tsum+= tend - tstart;\
tcount++;\
}else\
tskip_count++;\
if(((tcount+tskip_count)&(tcount+tskip_count-1))==0){\
av_log(NULL, AV_LOG_DEBUG, "%"PRIu64" dezicycles in %s, %d runs, %d skips\n", tsum*10/tcount, id, tcount, tskip_count);\
}\
}
#else
#define START_TIMER
#define STOP_TIMER(id) {}
#endif
#endif /* COMMON_H */
/*
* copyright (c) 2006 Michael Niedermayer <[email protected]>
*
* This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/**
* @file common.h
* common internal and external api header.
*/
#ifndef COMMON_H
#define COMMON_H
#if 0
#include <inttypes.h>
#endif
#ifdef HAVE_AV_CONFIG_H
/* only include the following when compiling package */
# include "config.h"
# include <stdlib.h>
# include <stdio.h>
# include <string.h>
# include <ctype.h>
# include <limits.h>
# include <errno.h>
# include <math.h>
#endif /* HAVE_AV_CONFIG_H */
#ifndef av_always_inline
#if defined(__GNUC__) && (__GNUC__ > 3 || __GNUC__ == 3 && __GNUC_MINOR__ > 0)
# define av_always_inline __attribute__((always_inline)) inline
# define av_noinline __attribute__((noinline))
#else
# define av_always_inline inline
# define av_noinline
#endif
#endif
#ifdef HAVE_AV_CONFIG_H
# include "internal.h"
#endif /* HAVE_AV_CONFIG_H */
#ifndef attribute_deprecated
#if defined(__GNUC__) && (__GNUC__ > 3 || __GNUC__ == 3 && __GNUC_MINOR__ > 0)
# define attribute_deprecated __attribute__((deprecated))
#else
# define attribute_deprecated
#endif
#endif
#include "mem.h"
//rounded divison & shift
#define RSHIFT(a,b) ((a) > 0 ? ((a) + ((1<<(b))>>1))>>(b) : ((a) + ((1<<(b))>>1)-1)>>(b))
/* assume b>0 */
#define ROUNDED_DIV(a,b) (((a)>0 ? (a) + ((b)>>1) : (a) - ((b)>>1))/(b))
#define FFABS(a) ((a) >= 0 ? (a) : (-(a)))
#define FFSIGN(a) ((a) > 0 ? 1 : -1)
#define FFMAX(a,b) ((a) > (b) ? (a) : (b))
#define FFMIN(a,b) ((a) > (b) ? (b) : (a))
#define FFSWAP(type,a,b) do{type SWAP_tmp= b; b= a; a= SWAP_tmp;}while(0)
/* misc math functions */
extern const uint8_t ff_log2_tab[256];
static inline int av_log2(unsigned int v)
{
int n;
n = 0;
if (v & 0xffff0000) {
v >>= 16;
n += 16;
}
if (v & 0xff00) {
v >>= 8;
n += 8;
}
n += ff_log2_tab[v];
return n;
}
static inline int av_log2_16bit(unsigned int v)
{
int n;
n = 0;
if (v & 0xff00) {
v >>= 8;
n += 8;
}
n += ff_log2_tab[v];
return n;
}
/* median of 3 */
static inline int mid_pred(int a, int b, int c)
{
#ifdef HAVE_CMOV
int i=b;
asm volatile(
"cmp %2, %1 \n\t"
"cmovg %1, %0 \n\t"
"cmovg %2, %1 \n\t"
"cmp %3, %1 \n\t"
"cmovl %3, %1 \n\t"
"cmp %1, %0 \n\t"
"cmovg %1, %0 \n\t"
:"+&r"(i), "+&r"(a)
:"r"(b), "r"(c)
);
return i;
#elif 0
int t= (a-b)&((a-b)>>31);
a-=t;
b+=t;
b-= (b-c)&((b-c)>>31);
b+= (a-b)&((a-b)>>31);
return b;
#else
if(a>b){
if(c>b){
if(c>a) b=a;
else b=c;
}
}else{
if(b>c){
if(c>a) b=c;
else b=a;
}
}
return b;
#endif
}
/**
* clip a signed integer value into the amin-amax range
* @param a value to clip
* @param amin minimum value of the clip range
* @param amax maximum value of the clip range
* @return clipped value
*/
static inline int av_clip(int a, int amin, int amax)
{
if (a < amin) return amin;
else if (a > amax) return amax;
else return a;
}
/**
* clip a signed integer value into the 0-255 range
* @param a value to clip
* @return clipped value
*/
static inline uint8_t av_clip_uint8(int a)
{
if (a&(~255)) return (-a)>>31;
else return a;
}
/* math */
int64_t ff_gcd(int64_t a, int64_t b);
/**
* converts fourcc string to int
*/
static inline int ff_get_fourcc(const char *s){
#ifdef HAVE_AV_CONFIG_H
assert( strlen(s)==4 );
#endif
return (s[0]) + (s[1]<<8) + (s[2]<<16) + (s[3]<<24);
}
#define MKTAG(a,b,c,d) (a | (b << 8) | (c << 16) | (d << 24))
#define MKBETAG(a,b,c,d) (d | (c << 8) | (b << 16) | (a << 24))
/*!
* \def GET_UTF8(val, GET_BYTE, ERROR)
* converts a utf-8 character (up to 4 bytes long) to its 32-bit ucs-4 encoded form
* \param val is the output and should be of type uint32_t. It holds the converted
* ucs-4 character and should be a left value.
* \param GET_BYTE gets utf-8 encoded bytes from any proper source. It can be
* a function or a statement whose return value or evaluated value is of type
* uint8_t. It will be executed up to 4 times for values in the valid utf-8 range,
* and up to 7 times in the general case.
* \param ERROR action that should be taken when an invalid utf-8 byte is returned
* from GET_BYTE. It should be a statement that jumps out of the macro,
* like exit(), goto, return, break, or continue.
*/
#define GET_UTF8(val, GET_BYTE, ERROR)\
val= GET_BYTE;\
{\
int ones= 7 - av_log2(val ^ 255);\
if(ones==1)\
ERROR\
val&= 127>>ones;\
while(--ones > 0){\
int tmp= GET_BYTE - 128;\
if(tmp>>6)\
ERROR\
val= (val<<6) + tmp;\
}\
}
/*!
* \def PUT_UTF8(val, tmp, PUT_BYTE)
* converts a 32-bit unicode character to its utf-8 encoded form (up to 4 bytes long).
* \param val is an input only argument and should be of type uint32_t. It holds
* a ucs4 encoded unicode character that is to be converted to utf-8. If
* val is given as a function it's executed only once.
* \param tmp is a temporary variable and should be of type uint8_t. It
* represents an intermediate value during conversion that is to be
* outputted by PUT_BYTE.
* \param PUT_BYTE writes the converted utf-8 bytes to any proper destination.
* It could be a function or a statement, and uses tmp as the input byte.
* For example, PUT_BYTE could be "*output++ = tmp;" PUT_BYTE will be
* executed up to 4 times for values in the valid utf-8 range and up to
* 7 times in the general case, depending on the length of the converted
* unicode character.
*/
#define PUT_UTF8(val, tmp, PUT_BYTE)\
{\
int bytes, shift;\
uint32_t in = val;\
if (in < 0x80) {\
tmp = in;\
PUT_BYTE\
} else {\
bytes = (av_log2(in) + 4) / 5;\
shift = (bytes - 1) * 6;\
tmp = (256 - (256 >> bytes)) | (in >> shift);\
PUT_BYTE\
while (shift >= 6) {\
shift -= 6;\
tmp = 0x80 | ((in >> shift) & 0x3f);\
PUT_BYTE\
}\
}\
}
#if defined(ARCH_X86) || defined(ARCH_POWERPC)
#if defined(ARCH_X86_64)
static inline uint64_t read_time(void)
{
uint64_t a, d;
asm volatile( "rdtsc\n\t"
: "=a" (a), "=d" (d)
);
return (d << 32) | (a & 0xffffffff);
}
#elif defined(ARCH_X86_32)
static inline long long read_time(void)
{
long long l;
asm volatile( "rdtsc\n\t"
: "=A" (l)
);
return l;
}
#else //FIXME check ppc64
static inline uint64_t read_time(void)
{
uint32_t tbu, tbl, temp;
/* from section 2.2.1 of the 32-bit PowerPC PEM */
__asm__ __volatile__(
"1:\n"
"mftbu %2\n"
"mftb %0\n"
"mftbu %1\n"
"cmpw %2,%1\n"
"bne 1b\n"
: "=r"(tbl), "=r"(tbu), "=r"(temp)
:
: "cc");
return (((uint64_t)tbu)<<32) | (uint64_t)tbl;
}
#endif
#define START_TIMER \
uint64_t tend;\
uint64_t tstart= read_time();\
#define STOP_TIMER(id) \
tend= read_time();\
{\
static uint64_t tsum=0;\
static int tcount=0;\
static int tskip_count=0;\
if(tcount<2 || tend - tstart < FFMAX(8*tsum/tcount, 2000)){\
tsum+= tend - tstart;\
tcount++;\
}else\
tskip_count++;\
if(((tcount+tskip_count)&(tcount+tskip_count-1))==0){\
av_log(NULL, AV_LOG_DEBUG, "%"PRIu64" dezicycles in %s, %d runs, %d skips\n", tsum*10/tcount, id, tcount, tskip_count);\
}\
}
#else
#define START_TIMER
#define STOP_TIMER(id) {}
#endif
#endif /* COMMON_H */
+82 -82
View File
@@ -1,82 +1,82 @@
/*
* arbitrary precision integers
* Copyright (c) 2004 Michael Niedermayer <[email protected]>
*
* This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
/**
* @file integer.h
* arbitrary precision integers
* @author Michael Niedermayer <[email protected]>
*/
#ifndef INTEGER_H
#define INTEGER_H
#define AV_INTEGER_SIZE 8
typedef struct AVInteger{
uint16_t v[AV_INTEGER_SIZE];
} AVInteger;
AVInteger av_add_i(AVInteger a, AVInteger b);
AVInteger av_sub_i(AVInteger a, AVInteger b);
/**
* returns the rounded down value of the logarithm of base 2 of the given AVInteger.
* this is simply the index of the most significant bit which is 1. Or 0 of all bits are 0
*/
int av_log2_i(AVInteger a);
AVInteger av_mul_i(AVInteger a, AVInteger b);
/**
* returns 0 if a==b, 1 if a>b and -1 if a<b.
*/
int av_cmp_i(AVInteger a, AVInteger b);
/**
* bitwise shift.
* @param s the number of bits by which the value should be shifted right, may be negative for shifting left
*/
AVInteger av_shr_i(AVInteger a, int s);
/**
* returns a % b.
* @param quot a/b will be stored here
*/
AVInteger av_mod_i(AVInteger *quot, AVInteger a, AVInteger b);
/**
* returns a/b.
*/
AVInteger av_div_i(AVInteger a, AVInteger b);
/**
* converts the given int64_t to an AVInteger.
*/
AVInteger av_int2i(int64_t a);
/**
* converts the given AVInteger to an int64_t.
* if the AVInteger is too large to fit into an int64_t,
* then only the least significant 64bit will be used
*/
int64_t av_i2int(AVInteger a);
#endif // INTEGER_H
/*
* arbitrary precision integers
* Copyright (c) 2004 Michael Niedermayer <[email protected]>
*
* This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
/**
* @file integer.h
* arbitrary precision integers
* @author Michael Niedermayer <[email protected]>
*/
#ifndef INTEGER_H
#define INTEGER_H
#define AV_INTEGER_SIZE 8
typedef struct AVInteger{
uint16_t v[AV_INTEGER_SIZE];
} AVInteger;
AVInteger av_add_i(AVInteger a, AVInteger b);
AVInteger av_sub_i(AVInteger a, AVInteger b);
/**
* returns the rounded down value of the logarithm of base 2 of the given AVInteger.
* this is simply the index of the most significant bit which is 1. Or 0 of all bits are 0
*/
int av_log2_i(AVInteger a);
AVInteger av_mul_i(AVInteger a, AVInteger b);
/**
* returns 0 if a==b, 1 if a>b and -1 if a<b.
*/
int av_cmp_i(AVInteger a, AVInteger b);
/**
* bitwise shift.
* @param s the number of bits by which the value should be shifted right, may be negative for shifting left
*/
AVInteger av_shr_i(AVInteger a, int s);
/**
* returns a % b.
* @param quot a/b will be stored here
*/
AVInteger av_mod_i(AVInteger *quot, AVInteger a, AVInteger b);
/**
* returns a/b.
*/
AVInteger av_div_i(AVInteger a, AVInteger b);
/**
* converts the given int64_t to an AVInteger.
*/
AVInteger av_int2i(int64_t a);
/**
* converts the given AVInteger to an int64_t.
* if the AVInteger is too large to fit into an int64_t,
* then only the least significant 64bit will be used
*/
int64_t av_i2int(AVInteger a);
#endif // INTEGER_H
+39 -39
View File
@@ -1,39 +1,39 @@
/*
* copyright (c) 2005 Michael Niedermayer <[email protected]>
*
* This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef INTFLOAT_READWRITE_H
#define INTFLOAT_READWRITE_H
#include "common.h"
/* IEEE 80 bits extended float */
typedef struct AVExtFloat {
uint8_t exponent[2];
uint8_t mantissa[8];
} AVExtFloat;
double av_int2dbl(int64_t v);
float av_int2flt(int32_t v);
double av_ext2dbl(const AVExtFloat ext);
int64_t av_dbl2int(double d);
int32_t av_flt2int(float d);
AVExtFloat av_dbl2ext(double d);
#endif /* INTFLOAT_READWRITE_H */
/*
* copyright (c) 2005 Michael Niedermayer <[email protected]>
*
* This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef INTFLOAT_READWRITE_H
#define INTFLOAT_READWRITE_H
#include "common.h"
/* IEEE 80 bits extended float */
typedef struct AVExtFloat {
uint8_t exponent[2];
uint8_t mantissa[8];
} AVExtFloat;
double av_int2dbl(int64_t v);
float av_int2flt(int32_t v);
double av_ext2dbl(const AVExtFloat ext);
int64_t av_dbl2int(double d);
int32_t av_flt2int(float d);
AVExtFloat av_dbl2ext(double d);
#endif /* INTFLOAT_READWRITE_H */
+116 -116
View File
@@ -1,116 +1,116 @@
/*
* copyright (c) 2006 Michael Niedermayer <[email protected]>
*
* This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef LOG_H
#define LOG_H
#include <stdarg.h>
/**
* Used by av_log
*/
typedef struct AVCLASS AVClass;
struct AVCLASS {
const char* class_name;
const char* (*item_name)(void*); /* actually passing a pointer to an AVCodecContext
or AVFormatContext, which begin with an AVClass.
Needed because av_log is in libavcodec and has no visibility
of AVIn/OutputFormat */
const struct AVOption *option;
};
/* av_log API */
#if LIBAVUTIL_VERSION_INT < (50<<16)
#define AV_LOG_QUIET -1
#define AV_LOG_FATAL 0
#define AV_LOG_ERROR 0
#define AV_LOG_WARNING 1
#define AV_LOG_INFO 1
#define AV_LOG_VERBOSE 1
#define AV_LOG_DEBUG 2
#else
#define AV_LOG_QUIET -8
/**
* something went really wrong and we will crash now
*/
#define AV_LOG_PANIC 0
/**
* something went wrong and recovery is not possible
* like no header in a format which depends on it or a combination
* of parameters which are not allowed
*/
#define AV_LOG_FATAL 8
/**
* something went wrong and cannot losslessly be recovered
* but not all future data is affected
*/
#define AV_LOG_ERROR 16
/**
* something somehow does not look correct / something which may or may not
* lead to some problems like use of -vstrict -2
*/
#define AV_LOG_WARNING 24
#define AV_LOG_INFO 32
#define AV_LOG_VERBOSE 40
/**
* stuff which is only useful for libav* developers
*/
#define AV_LOG_DEBUG 48
#endif
extern int av_log_level;
/**
* Send the specified message to the log if the level is less than or equal to
* the current av_log_level. By default, all logging messages are sent to
* stderr. This behavior can be altered by setting a different av_vlog callback
* function.
*
* @param avcl A pointer to an arbitrary struct of which the first field is a
* pointer to an AVClass struct.
* @param level The importance level of the message, lower values signifying
* higher importance.
* @param fmt The format string (printf-compatible) that specifies how
* subsequent arguments are converted to output.
* @see av_vlog
*/
#ifdef __GNUC__
extern void av_log(void*, int level, const char *fmt, ...) __attribute__ ((__format__ (__printf__, 3, 4)));
#else
extern void av_log(void*, int level, const char *fmt, ...);
#endif
#if LIBAVUTIL_VERSION_INT < (50<<16)
extern void av_vlog(void*, int level, const char *fmt, va_list);
extern int av_log_get_level(void);
extern void av_log_set_level(int);
extern void av_log_set_callback(void (*)(void*, int, const char*, va_list));
extern void av_log_default_callback(void* ptr, int level, const char* fmt, va_list vl);
#else
extern void (*av_vlog)(void*, int, const char*, va_list);
#endif
#endif /* LOG_H */
/*
* copyright (c) 2006 Michael Niedermayer <[email protected]>
*
* This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef LOG_H
#define LOG_H
#include <stdarg.h>
/**
* Used by av_log
*/
typedef struct AVCLASS AVClass;
struct AVCLASS {
const char* class_name;
const char* (*item_name)(void*); /* actually passing a pointer to an AVCodecContext
or AVFormatContext, which begin with an AVClass.
Needed because av_log is in libavcodec and has no visibility
of AVIn/OutputFormat */
const struct AVOption *option;
};
/* av_log API */
#if LIBAVUTIL_VERSION_INT < (50<<16)
#define AV_LOG_QUIET -1
#define AV_LOG_FATAL 0
#define AV_LOG_ERROR 0
#define AV_LOG_WARNING 1
#define AV_LOG_INFO 1
#define AV_LOG_VERBOSE 1
#define AV_LOG_DEBUG 2
#else
#define AV_LOG_QUIET -8
/**
* something went really wrong and we will crash now
*/
#define AV_LOG_PANIC 0
/**
* something went wrong and recovery is not possible
* like no header in a format which depends on it or a combination
* of parameters which are not allowed
*/
#define AV_LOG_FATAL 8
/**
* something went wrong and cannot losslessly be recovered
* but not all future data is affected
*/
#define AV_LOG_ERROR 16
/**
* something somehow does not look correct / something which may or may not
* lead to some problems like use of -vstrict -2
*/
#define AV_LOG_WARNING 24
#define AV_LOG_INFO 32
#define AV_LOG_VERBOSE 40
/**
* stuff which is only useful for libav* developers
*/
#define AV_LOG_DEBUG 48
#endif
extern int av_log_level;
/**
* Send the specified message to the log if the level is less than or equal to
* the current av_log_level. By default, all logging messages are sent to
* stderr. This behavior can be altered by setting a different av_vlog callback
* function.
*
* @param avcl A pointer to an arbitrary struct of which the first field is a
* pointer to an AVClass struct.
* @param level The importance level of the message, lower values signifying
* higher importance.
* @param fmt The format string (printf-compatible) that specifies how
* subsequent arguments are converted to output.
* @see av_vlog
*/
#ifdef __GNUC__
extern void av_log(void*, int level, const char *fmt, ...) __attribute__ ((__format__ (__printf__, 3, 4)));
#else
extern void av_log(void*, int level, const char *fmt, ...);
#endif
#if LIBAVUTIL_VERSION_INT < (50<<16)
extern void av_vlog(void*, int level, const char *fmt, va_list);
extern int av_log_get_level(void);
extern void av_log_set_level(int);
extern void av_log_set_callback(void (*)(void*, int, const char*, va_list));
extern void av_log_default_callback(void* ptr, int level, const char* fmt, va_list vl);
#else
extern void (*av_vlog)(void*, int, const char*, va_list);
#endif
#endif /* LOG_H */
+51 -51
View File
@@ -1,51 +1,51 @@
/*
* copyright (c) 2005 Michael Niedermayer <[email protected]>
*
* This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef MATHEMATICS_H
#define MATHEMATICS_H
#include "rational.h"
enum AVRounding {
AV_ROUND_ZERO = 0, ///< round toward zero
AV_ROUND_INF = 1, ///< round away from zero
AV_ROUND_DOWN = 2, ///< round toward -infinity
AV_ROUND_UP = 3, ///< round toward +infinity
AV_ROUND_NEAR_INF = 5, ///< round to nearest and halfway cases away from zero
};
/**
* rescale a 64bit integer with rounding to nearest.
* a simple a*b/c isn't possible as it can overflow
*/
int64_t av_rescale(int64_t a, int64_t b, int64_t c);
/**
* rescale a 64bit integer with specified rounding.
* a simple a*b/c isn't possible as it can overflow
*/
int64_t av_rescale_rnd(int64_t a, int64_t b, int64_t c, enum AVRounding);
/**
* rescale a 64bit integer by 2 rational numbers.
*/
int64_t av_rescale_q(int64_t a, AVRational bq, AVRational cq);
#endif /* MATHEMATICS_H */
/*
* copyright (c) 2005 Michael Niedermayer <[email protected]>
*
* This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef MATHEMATICS_H
#define MATHEMATICS_H
#include "rational.h"
enum AVRounding {
AV_ROUND_ZERO = 0, ///< round toward zero
AV_ROUND_INF = 1, ///< round away from zero
AV_ROUND_DOWN = 2, ///< round toward -infinity
AV_ROUND_UP = 3, ///< round toward +infinity
AV_ROUND_NEAR_INF = 5, ///< round to nearest and halfway cases away from zero
};
/**
* rescale a 64bit integer with rounding to nearest.
* a simple a*b/c isn't possible as it can overflow
*/
int64_t av_rescale(int64_t a, int64_t b, int64_t c);
/**
* rescale a 64bit integer with specified rounding.
* a simple a*b/c isn't possible as it can overflow
*/
int64_t av_rescale_rnd(int64_t a, int64_t b, int64_t c, enum AVRounding);
/**
* rescale a 64bit integer by 2 rational numbers.
*/
int64_t av_rescale_q(int64_t a, AVRational bq, AVRational cq);
#endif /* MATHEMATICS_H */
+65 -65
View File
@@ -1,65 +1,65 @@
/*
* copyright (c) 2006 Michael Niedermayer <[email protected]>
*
* This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/**
* @file mem.h
* Memory handling functions.
*/
#ifndef AV_MEM_H
#define AV_MEM_H
#ifdef __GNUC__
#define DECLARE_ALIGNED(n,t,v) t v __attribute__ ((aligned (n)))
#else
#define DECLARE_ALIGNED(n,t,v) __declspec(align(n)) t v
#endif
/**
* Memory allocation of size byte with alignment suitable for all
* memory accesses (including vectors if available on the
* CPU). av_malloc(0) must return a non NULL pointer.
*/
void *av_malloc(unsigned int size);
/**
* av_realloc semantics (same as glibc): if ptr is NULL and size > 0,
* identical to malloc(size). If size is zero, it is identical to
* free(ptr) and NULL is returned.
*/
void *av_realloc(void *ptr, unsigned int size);
/**
* Free memory which has been allocated with av_malloc(z)() or av_realloc().
* NOTE: ptr = NULL is explicetly allowed
* Note2: it is recommended that you use av_freep() instead
*/
void av_free(void *ptr);
void *av_mallocz(unsigned int size);
char *av_strdup(const char *s);
/**
* Frees memory and sets the pointer to NULL.
* @param ptr pointer to the pointer which should be freed
*/
void av_freep(void *ptr);
#endif /* AV_MEM_H */
/*
* copyright (c) 2006 Michael Niedermayer <[email protected]>
*
* This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/**
* @file mem.h
* Memory handling functions.
*/
#ifndef AV_MEM_H
#define AV_MEM_H
#ifdef __GNUC__
#define DECLARE_ALIGNED(n,t,v) t v __attribute__ ((aligned (n)))
#else
#define DECLARE_ALIGNED(n,t,v) __declspec(align(n)) t v
#endif
/**
* Memory allocation of size byte with alignment suitable for all
* memory accesses (including vectors if available on the
* CPU). av_malloc(0) must return a non NULL pointer.
*/
void *av_malloc(unsigned int size);
/**
* av_realloc semantics (same as glibc): if ptr is NULL and size > 0,
* identical to malloc(size). If size is zero, it is identical to
* free(ptr) and NULL is returned.
*/
void *av_realloc(void *ptr, unsigned int size);
/**
* Free memory which has been allocated with av_malloc(z)() or av_realloc().
* NOTE: ptr = NULL is explicetly allowed
* Note2: it is recommended that you use av_freep() instead
*/
void av_free(void *ptr);
void *av_mallocz(unsigned int size);
char *av_strdup(const char *s);
/**
* Frees memory and sets the pointer to NULL.
* @param ptr pointer to the pointer which should be freed
*/
void av_freep(void *ptr);
#endif /* AV_MEM_H */
+114 -114
View File
@@ -1,114 +1,114 @@
/*
* Rational numbers
* Copyright (c) 2003 Michael Niedermayer <[email protected]>
*
* This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
/**
* @file rational.h
* Rational numbers.
* @author Michael Niedermayer <[email protected]>
*/
#ifndef RATIONAL_H
#define RATIONAL_H
/**
* Rational number num/den.
*/
typedef struct AVRational{
int num; ///< numerator
int den; ///< denominator
} AVRational;
/**
* Compare two rationals.
* @param a first rational
* @param b second rational
* @return 0 if a==b, 1 if a>b and -1 if a<b.
*/
static inline int av_cmp_q(AVRational a, AVRational b){
const int64_t tmp= a.num * (int64_t)b.den - b.num * (int64_t)a.den;
if(tmp) return (int)((tmp>>63)|1);
else return 0;
}
/**
* Rational to double conversion.
* @param a rational to convert
* @return (double) a
*/
static inline double av_q2d(AVRational a){
return a.num / (double) a.den;
}
/**
* Reduce a fraction.
* This is useful for framerate calculations.
* @param dst_nom destination numerator
* @param dst_den destination denominator
* @param nom source numerator
* @param den source denominator
* @param max the maximum allowed for dst_nom & dst_den
* @return 1 if exact, 0 otherwise
*/
int av_reduce(int *dst_nom, int *dst_den, int64_t nom, int64_t den, int64_t max);
/**
* Multiplies two rationals.
* @param b first rational.
* @param c second rational.
* @return b*c.
*/
AVRational av_mul_q(AVRational b, AVRational c);
/**
* Divides one rational by another.
* @param b first rational.
* @param c second rational.
* @return b/c.
*/
AVRational av_div_q(AVRational b, AVRational c);
/**
* Adds two rationals.
* @param b first rational.
* @param c second rational.
* @return b+c.
*/
AVRational av_add_q(AVRational b, AVRational c);
/**
* Subtracts one rational from another.
* @param b first rational.
* @param c second rational.
* returns b-c.
*/
AVRational av_sub_q(AVRational b, AVRational c);
/**
* Converts a double precision floating point number to a rational.
* @param d double to convert
* @param max the maximum allowed numerator and denominator
* @return (AVRational) d.
*/
AVRational av_d2q(double d, int max);
#endif // RATIONAL_H
/*
* Rational numbers
* Copyright (c) 2003 Michael Niedermayer <[email protected]>
*
* This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
/**
* @file rational.h
* Rational numbers.
* @author Michael Niedermayer <[email protected]>
*/
#ifndef RATIONAL_H
#define RATIONAL_H
/**
* Rational number num/den.
*/
typedef struct AVRational{
int num; ///< numerator
int den; ///< denominator
} AVRational;
/**
* Compare two rationals.
* @param a first rational
* @param b second rational
* @return 0 if a==b, 1 if a>b and -1 if a<b.
*/
static inline int av_cmp_q(AVRational a, AVRational b){
const int64_t tmp= a.num * (int64_t)b.den - b.num * (int64_t)a.den;
if(tmp) return (int)((tmp>>63)|1);
else return 0;
}
/**
* Rational to double conversion.
* @param a rational to convert
* @return (double) a
*/
static inline double av_q2d(AVRational a){
return a.num / (double) a.den;
}
/**
* Reduce a fraction.
* This is useful for framerate calculations.
* @param dst_nom destination numerator
* @param dst_den destination denominator
* @param nom source numerator
* @param den source denominator
* @param max the maximum allowed for dst_nom & dst_den
* @return 1 if exact, 0 otherwise
*/
int av_reduce(int *dst_nom, int *dst_den, int64_t nom, int64_t den, int64_t max);
/**
* Multiplies two rationals.
* @param b first rational.
* @param c second rational.
* @return b*c.
*/
AVRational av_mul_q(AVRational b, AVRational c);
/**
* Divides one rational by another.
* @param b first rational.
* @param c second rational.
* @return b/c.
*/
AVRational av_div_q(AVRational b, AVRational c);
/**
* Adds two rationals.
* @param b first rational.
* @param c second rational.
* @return b+c.
*/
AVRational av_add_q(AVRational b, AVRational c);
/**
* Subtracts one rational from another.
* @param b first rational.
* @param c second rational.
* returns b-c.
*/
AVRational av_sub_q(AVRational b, AVRational c);
/**
* Converts a double precision floating point number to a rational.
* @param d double to convert
* @param max the maximum allowed numerator and denominator
* @return (AVRational) d.
*/
AVRational av_d2q(double d, int max);
#endif // RATIONAL_H
+127 -127
View File
@@ -1,127 +1,127 @@
/*
* RTP definitions
* Copyright (c) 2002 Fabrice Bellard.
*
* This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef RTP_H
#define RTP_H
#define RTP_MIN_PACKET_LENGTH 12
#define RTP_MAX_PACKET_LENGTH 1500 /* XXX: suppress this define */
int rtp_init(void);
int rtp_get_codec_info(AVCodecContext *codec, int payload_type);
/** return < 0 if unknown payload type */
int rtp_get_payload_type(AVCodecContext *codec);
typedef struct RTPDemuxContext RTPDemuxContext;
typedef struct rtp_payload_data_s rtp_payload_data_s;
RTPDemuxContext *rtp_parse_open(AVFormatContext *s1, AVStream *st, URLContext *rtpc, int payload_type, rtp_payload_data_s *rtp_payload_data);
int rtp_parse_packet(RTPDemuxContext *s, AVPacket *pkt,
const uint8_t *buf, int len);
void rtp_parse_close(RTPDemuxContext *s);
extern AVOutputFormat rtp_muxer;
extern AVInputFormat rtp_demuxer;
int rtp_get_local_port(URLContext *h);
int rtp_set_remote_url(URLContext *h, const char *uri);
void rtp_get_file_handles(URLContext *h, int *prtp_fd, int *prtcp_fd);
/**
* some rtp servers assume client is dead if they don't hear from them...
* so we send a Receiver Report to the provided ByteIO context
* (we don't have access to the rtcp handle from here)
*/
int rtp_check_and_send_back_rr(RTPDemuxContext *s, int count);
extern URLProtocol rtp_protocol;
#define RTP_PT_PRIVATE 96
#define RTP_VERSION 2
#define RTP_MAX_SDES 256 /**< maximum text length for SDES */
/* RTCP paquets use 0.5 % of the bandwidth */
#define RTCP_TX_RATIO_NUM 5
#define RTCP_TX_RATIO_DEN 1000
/** Structure listing useful vars to parse RTP packet payload*/
typedef struct rtp_payload_data_s
{
int sizelength;
int indexlength;
int indexdeltalength;
int profile_level_id;
int streamtype;
int objecttype;
char *mode;
/** mpeg 4 AU headers */
struct AUHeaders {
int size;
int index;
int cts_flag;
int cts;
int dts_flag;
int dts;
int rap_flag;
int streamstate;
} *au_headers;
int nb_au_headers;
int au_headers_length_bytes;
int cur_au_index;
} rtp_payload_data_t;
typedef struct AVRtpPayloadType_s
{
int pt;
const char enc_name[50]; /* XXX: why 50 ? */
enum CodecType codec_type;
enum CodecID codec_id;
int clock_rate;
int audio_channels;
} AVRtpPayloadType_t;
#if 0
typedef enum {
RTCP_SR = 200,
RTCP_RR = 201,
RTCP_SDES = 202,
RTCP_BYE = 203,
RTCP_APP = 204
} rtcp_type_t;
typedef enum {
RTCP_SDES_END = 0,
RTCP_SDES_CNAME = 1,
RTCP_SDES_NAME = 2,
RTCP_SDES_EMAIL = 3,
RTCP_SDES_PHONE = 4,
RTCP_SDES_LOC = 5,
RTCP_SDES_TOOL = 6,
RTCP_SDES_NOTE = 7,
RTCP_SDES_PRIV = 8,
RTCP_SDES_IMG = 9,
RTCP_SDES_DOOR = 10,
RTCP_SDES_SOURCE = 11
} rtcp_sdes_type_t;
#endif
extern AVRtpPayloadType_t AVRtpPayloadTypes[];
#endif /* RTP_H */
/*
* RTP definitions
* Copyright (c) 2002 Fabrice Bellard.
*
* This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef RTP_H
#define RTP_H
#define RTP_MIN_PACKET_LENGTH 12
#define RTP_MAX_PACKET_LENGTH 1500 /* XXX: suppress this define */
int rtp_init(void);
int rtp_get_codec_info(AVCodecContext *codec, int payload_type);
/** return < 0 if unknown payload type */
int rtp_get_payload_type(AVCodecContext *codec);
typedef struct RTPDemuxContext RTPDemuxContext;
typedef struct rtp_payload_data_s rtp_payload_data_s;
RTPDemuxContext *rtp_parse_open(AVFormatContext *s1, AVStream *st, URLContext *rtpc, int payload_type, rtp_payload_data_s *rtp_payload_data);
int rtp_parse_packet(RTPDemuxContext *s, AVPacket *pkt,
const uint8_t *buf, int len);
void rtp_parse_close(RTPDemuxContext *s);
extern AVOutputFormat rtp_muxer;
extern AVInputFormat rtp_demuxer;
int rtp_get_local_port(URLContext *h);
int rtp_set_remote_url(URLContext *h, const char *uri);
void rtp_get_file_handles(URLContext *h, int *prtp_fd, int *prtcp_fd);
/**
* some rtp servers assume client is dead if they don't hear from them...
* so we send a Receiver Report to the provided ByteIO context
* (we don't have access to the rtcp handle from here)
*/
int rtp_check_and_send_back_rr(RTPDemuxContext *s, int count);
extern URLProtocol rtp_protocol;
#define RTP_PT_PRIVATE 96
#define RTP_VERSION 2
#define RTP_MAX_SDES 256 /**< maximum text length for SDES */
/* RTCP paquets use 0.5 % of the bandwidth */
#define RTCP_TX_RATIO_NUM 5
#define RTCP_TX_RATIO_DEN 1000
/** Structure listing useful vars to parse RTP packet payload*/
typedef struct rtp_payload_data_s
{
int sizelength;
int indexlength;
int indexdeltalength;
int profile_level_id;
int streamtype;
int objecttype;
char *mode;
/** mpeg 4 AU headers */
struct AUHeaders {
int size;
int index;
int cts_flag;
int cts;
int dts_flag;
int dts;
int rap_flag;
int streamstate;
} *au_headers;
int nb_au_headers;
int au_headers_length_bytes;
int cur_au_index;
} rtp_payload_data_t;
typedef struct AVRtpPayloadType_s
{
int pt;
const char enc_name[50]; /* XXX: why 50 ? */
enum CodecType codec_type;
enum CodecID codec_id;
int clock_rate;
int audio_channels;
} AVRtpPayloadType_t;
#if 0
typedef enum {
RTCP_SR = 200,
RTCP_RR = 201,
RTCP_SDES = 202,
RTCP_BYE = 203,
RTCP_APP = 204
} rtcp_type_t;
typedef enum {
RTCP_SDES_END = 0,
RTCP_SDES_CNAME = 1,
RTCP_SDES_NAME = 2,
RTCP_SDES_EMAIL = 3,
RTCP_SDES_PHONE = 4,
RTCP_SDES_LOC = 5,
RTCP_SDES_TOOL = 6,
RTCP_SDES_NOTE = 7,
RTCP_SDES_PRIV = 8,
RTCP_SDES_IMG = 9,
RTCP_SDES_DOOR = 10,
RTCP_SDES_SOURCE = 11
} rtcp_sdes_type_t;
#endif
extern AVRtpPayloadType_t AVRtpPayloadTypes[];
#endif /* RTP_H */
+94 -94
View File
@@ -1,94 +1,94 @@
/*
* RTSP definitions
* Copyright (c) 2002 Fabrice Bellard.
*
* This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef RTSP_H
#define RTSP_H
#include "rtspcodes.h"
enum RTSPProtocol {
RTSP_PROTOCOL_RTP_UDP = 0,
RTSP_PROTOCOL_RTP_TCP = 1,
RTSP_PROTOCOL_RTP_UDP_MULTICAST = 2,
};
#define RTSP_DEFAULT_PORT 554
#define RTSP_MAX_TRANSPORTS 8
#define RTSP_TCP_MAX_PACKET_SIZE 1472
#define RTSP_DEFAULT_NB_AUDIO_CHANNELS 2
#define RTSP_DEFAULT_AUDIO_SAMPLERATE 44100
#define RTSP_RTP_PORT_MIN 5000
#define RTSP_RTP_PORT_MAX 10000
typedef struct RTSPTransportField {
int interleaved_min, interleaved_max; /**< interleave ids, if TCP transport */
int port_min, port_max; /**< RTP ports */
int client_port_min, client_port_max; /**< RTP ports */
int server_port_min, server_port_max; /**< RTP ports */
int ttl; /**< ttl value */
uint32_t destination; /**< destination IP address */
enum RTSPProtocol protocol;
} RTSPTransportField;
typedef struct RTSPHeader {
int content_length;
enum RTSPStatusCode status_code; /**< response code from server */
int nb_transports;
/** in AV_TIME_BASE unit, AV_NOPTS_VALUE if not used */
int64_t range_start, range_end;
RTSPTransportField transports[RTSP_MAX_TRANSPORTS];
int seq; /**< sequence number */
char session_id[512];
} RTSPHeader;
/** the callback can be used to extend the connection setup/teardown step */
enum RTSPCallbackAction {
RTSP_ACTION_SERVER_SETUP,
RTSP_ACTION_SERVER_TEARDOWN,
RTSP_ACTION_CLIENT_SETUP,
RTSP_ACTION_CLIENT_TEARDOWN,
};
typedef struct RTSPActionServerSetup {
uint32_t ipaddr;
char transport_option[512];
} RTSPActionServerSetup;
typedef int FFRTSPCallback(enum RTSPCallbackAction action,
const char *session_id,
char *buf, int buf_size,
void *arg);
/** useful for modules: set RTSP callback function */
void rtsp_set_callback(FFRTSPCallback *rtsp_cb);
int rtsp_init(void);
void rtsp_parse_line(RTSPHeader *reply, const char *buf);
extern int rtsp_default_protocols;
extern int rtsp_rtp_port_min;
extern int rtsp_rtp_port_max;
extern FFRTSPCallback *ff_rtsp_callback;
extern AVInputFormat rtsp_demuxer;
int rtsp_pause(AVFormatContext *s);
int rtsp_resume(AVFormatContext *s);
#endif /* RTSP_H */
/*
* RTSP definitions
* Copyright (c) 2002 Fabrice Bellard.
*
* This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef RTSP_H
#define RTSP_H
#include "rtspcodes.h"
enum RTSPProtocol {
RTSP_PROTOCOL_RTP_UDP = 0,
RTSP_PROTOCOL_RTP_TCP = 1,
RTSP_PROTOCOL_RTP_UDP_MULTICAST = 2,
};
#define RTSP_DEFAULT_PORT 554
#define RTSP_MAX_TRANSPORTS 8
#define RTSP_TCP_MAX_PACKET_SIZE 1472
#define RTSP_DEFAULT_NB_AUDIO_CHANNELS 2
#define RTSP_DEFAULT_AUDIO_SAMPLERATE 44100
#define RTSP_RTP_PORT_MIN 5000
#define RTSP_RTP_PORT_MAX 10000
typedef struct RTSPTransportField {
int interleaved_min, interleaved_max; /**< interleave ids, if TCP transport */
int port_min, port_max; /**< RTP ports */
int client_port_min, client_port_max; /**< RTP ports */
int server_port_min, server_port_max; /**< RTP ports */
int ttl; /**< ttl value */
uint32_t destination; /**< destination IP address */
enum RTSPProtocol protocol;
} RTSPTransportField;
typedef struct RTSPHeader {
int content_length;
enum RTSPStatusCode status_code; /**< response code from server */
int nb_transports;
/** in AV_TIME_BASE unit, AV_NOPTS_VALUE if not used */
int64_t range_start, range_end;
RTSPTransportField transports[RTSP_MAX_TRANSPORTS];
int seq; /**< sequence number */
char session_id[512];
} RTSPHeader;
/** the callback can be used to extend the connection setup/teardown step */
enum RTSPCallbackAction {
RTSP_ACTION_SERVER_SETUP,
RTSP_ACTION_SERVER_TEARDOWN,
RTSP_ACTION_CLIENT_SETUP,
RTSP_ACTION_CLIENT_TEARDOWN,
};
typedef struct RTSPActionServerSetup {
uint32_t ipaddr;
char transport_option[512];
} RTSPActionServerSetup;
typedef int FFRTSPCallback(enum RTSPCallbackAction action,
const char *session_id,
char *buf, int buf_size,
void *arg);
/** useful for modules: set RTSP callback function */
void rtsp_set_callback(FFRTSPCallback *rtsp_cb);
int rtsp_init(void);
void rtsp_parse_line(RTSPHeader *reply, const char *buf);
extern int rtsp_default_protocols;
extern int rtsp_rtp_port_min;
extern int rtsp_rtp_port_max;
extern FFRTSPCallback *ff_rtsp_callback;
extern AVInputFormat rtsp_demuxer;
int rtsp_pause(AVFormatContext *s);
int rtsp_resume(AVFormatContext *s);
#endif /* RTSP_H */
+36 -36
View File
@@ -1,36 +1,36 @@
/*
* RTSP definitions
* copyright (c) 2002 Fabrice Bellard
*
* This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/** RTSP handling */
enum RTSPStatusCode {
RTSP_STATUS_OK =200, /**< OK */
RTSP_STATUS_METHOD =405, /**< Method Not Allowed */
RTSP_STATUS_BANDWIDTH =453, /**< Not Enough Bandwidth */
RTSP_STATUS_SESSION =454, /**< Session Not Found */
RTSP_STATUS_STATE =455, /**< Method Not Valid in This State */
RTSP_STATUS_AGGREGATE =459, /**< Aggregate operation not allowed */
RTSP_STATUS_ONLY_AGGREGATE =460, /**< Only aggregate operation allowed */
RTSP_STATUS_TRANSPORT =461, /**< Unsupported transport */
RTSP_STATUS_INTERNAL =500, /**< Internal Server Error */
RTSP_STATUS_SERVICE =503, /**< Service Unavailable */
RTSP_STATUS_VERSION =505, /**< RTSP Version not supported */
};
/*
* RTSP definitions
* copyright (c) 2002 Fabrice Bellard
*
* This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/** RTSP handling */
enum RTSPStatusCode {
RTSP_STATUS_OK =200, /**< OK */
RTSP_STATUS_METHOD =405, /**< Method Not Allowed */
RTSP_STATUS_BANDWIDTH =453, /**< Not Enough Bandwidth */
RTSP_STATUS_SESSION =454, /**< Session Not Found */
RTSP_STATUS_STATE =455, /**< Method Not Valid in This State */
RTSP_STATUS_AGGREGATE =459, /**< Aggregate operation not allowed */
RTSP_STATUS_ONLY_AGGREGATE =460, /**< Only aggregate operation allowed */
RTSP_STATUS_TRANSPORT =461, /**< Unsupported transport */
RTSP_STATUS_INTERNAL =500, /**< Internal Server Error */
RTSP_STATUS_SERVICE =503, /**< Service Unavailable */
RTSP_STATUS_VERSION =505, /**< RTSP Version not supported */
};
+117 -117
View File
@@ -1,117 +1,117 @@
* Introduction:
=============
JSON (JavaScript Object Notation) is a lightweight data-interchange format.
It can represent integer, real number, string, an ordered sequence of
value, and a collection of name/value pairs.
JsonCpp is a simple API to manipulate JSON value, handle serialization
and unserialization to string.
It can also preserve existing comment in unserialization/serialization steps,
making it a convenient format to store user input files.
Unserialization parsing is user friendly and provides precise error reports.
* Building/Testing:
=================
JsonCpp uses Scons (http://www.scons.org) as a build system. Scons requires
python to be installed (http://www.python.org).
You download scons-local distribution from the following url:
http://sourceforge.net/project/showfiles.php?group_id=30337&package_id=67375
Unzip it in the directory where you found this README file. scons.py Should be
at the same level as README.
python scons.py platform=PLTFRM [TARGET]
where PLTFRM may be one of:
suncc Sun C++ (Solaris)
vacpp Visual Age C++ (AIX)
mingw
msvc6 Microsoft Visual Studio 6 service pack 5-6
msvc70 Microsoft Visual Studio 2002
msvc71 Microsoft Visual Studio 2003
msvc80 Microsoft Visual Studio 2005
linux-gcc Gnu C++ (linux, also reported to work for Mac OS X)
adding platform is fairly simple. You need to change the Sconstruct file
to do so.
and TARGET may be:
check: build library and run unit tests.
* Running the test manually:
==========================
cd test
# This will run the Reader/Writer tests
python runjsontests.py "path to jsontest.exe"
# This will run the Reader/Writer tests, using JSONChecker test suite
# (http://www.json.org/JSON_checker/).
# Notes: not all tests pass: JsonCpp is too lenient (for example,
# it allows an integer to start with '0'). The goal is to improve
# strict mode parsing to get all tests to pass.
python runjsontests.py --with-json-checker "path to jsontest.exe"
# This will run the unit tests (mostly Value)
python rununittests.py "path to test_lib_json.exe"
You can run the tests using valgrind:
python rununittests.py --valgrind "path to test_lib_json.exe"
* Building the documentation:
===========================
Run the python script doxybuild.py from the top directory:
python doxybuild.py --open --with-dot
See doxybuild.py --help for options.
* Adding a reader/writer test:
============================
To add a test, you need to create two files in test/data:
- a TESTNAME.json file, that contains the input document in JSON format.
- a TESTNAME.expected file, that contains a flatened representation of
the input document.
TESTNAME.expected file format:
- each line represents a JSON element of the element tree represented
by the input document.
- each line has two parts: the path to access the element separated from
the element value by '='. Array and object values are always empty
(e.g. represented by either [] or {}).
- element path: '.' represented the root element, and is used to separate
object members. [N] is used to specify the value of an array element
at index N.
See test_complex_01.json and test_complex_01.expected to better understand
element path.
* Understanding reader/writer test output:
========================================
When a test is run, output files are generated aside the input test files.
Below is a short description of the content of each file:
- test_complex_01.json: input JSON document
- test_complex_01.expected: flattened JSON element tree used to check if
parsing was corrected.
- test_complex_01.actual: flattened JSON element tree produced by
jsontest.exe from reading test_complex_01.json
- test_complex_01.rewrite: JSON document written by jsontest.exe using the
Json::Value parsed from test_complex_01.json and serialized using
Json::StyledWritter.
- test_complex_01.actual-rewrite: flattened JSON element tree produced by
jsontest.exe from reading test_complex_01.rewrite.
test_complex_01.process-output: jsontest.exe output, typically useful to
understand parsing error.
* Introduction:
=============
JSON (JavaScript Object Notation) is a lightweight data-interchange format.
It can represent integer, real number, string, an ordered sequence of
value, and a collection of name/value pairs.
JsonCpp is a simple API to manipulate JSON value, handle serialization
and unserialization to string.
It can also preserve existing comment in unserialization/serialization steps,
making it a convenient format to store user input files.
Unserialization parsing is user friendly and provides precise error reports.
* Building/Testing:
=================
JsonCpp uses Scons (http://www.scons.org) as a build system. Scons requires
python to be installed (http://www.python.org).
You download scons-local distribution from the following url:
http://sourceforge.net/project/showfiles.php?group_id=30337&package_id=67375
Unzip it in the directory where you found this README file. scons.py Should be
at the same level as README.
python scons.py platform=PLTFRM [TARGET]
where PLTFRM may be one of:
suncc Sun C++ (Solaris)
vacpp Visual Age C++ (AIX)
mingw
msvc6 Microsoft Visual Studio 6 service pack 5-6
msvc70 Microsoft Visual Studio 2002
msvc71 Microsoft Visual Studio 2003
msvc80 Microsoft Visual Studio 2005
linux-gcc Gnu C++ (linux, also reported to work for Mac OS X)
adding platform is fairly simple. You need to change the Sconstruct file
to do so.
and TARGET may be:
check: build library and run unit tests.
* Running the test manually:
==========================
cd test
# This will run the Reader/Writer tests
python runjsontests.py "path to jsontest.exe"
# This will run the Reader/Writer tests, using JSONChecker test suite
# (http://www.json.org/JSON_checker/).
# Notes: not all tests pass: JsonCpp is too lenient (for example,
# it allows an integer to start with '0'). The goal is to improve
# strict mode parsing to get all tests to pass.
python runjsontests.py --with-json-checker "path to jsontest.exe"
# This will run the unit tests (mostly Value)
python rununittests.py "path to test_lib_json.exe"
You can run the tests using valgrind:
python rununittests.py --valgrind "path to test_lib_json.exe"
* Building the documentation:
===========================
Run the python script doxybuild.py from the top directory:
python doxybuild.py --open --with-dot
See doxybuild.py --help for options.
* Adding a reader/writer test:
============================
To add a test, you need to create two files in test/data:
- a TESTNAME.json file, that contains the input document in JSON format.
- a TESTNAME.expected file, that contains a flatened representation of
the input document.
TESTNAME.expected file format:
- each line represents a JSON element of the element tree represented
by the input document.
- each line has two parts: the path to access the element separated from
the element value by '='. Array and object values are always empty
(e.g. represented by either [] or {}).
- element path: '.' represented the root element, and is used to separate
object members. [N] is used to specify the value of an array element
at index N.
See test_complex_01.json and test_complex_01.expected to better understand
element path.
* Understanding reader/writer test output:
========================================
When a test is run, output files are generated aside the input test files.
Below is a short description of the content of each file:
- test_complex_01.json: input JSON document
- test_complex_01.expected: flattened JSON element tree used to check if
parsing was corrected.
- test_complex_01.actual: flattened JSON element tree produced by
jsontest.exe from reading test_complex_01.json
- test_complex_01.rewrite: JSON document written by jsontest.exe using the
Json::Value parsed from test_complex_01.json and serialized using
Json::StyledWritter.
- test_complex_01.actual-rewrite: flattened JSON element tree produced by
jsontest.exe from reading test_complex_01.rewrite.
test_complex_01.process-output: jsontest.exe output, typically useful to
understand parsing error.
+1 -1
View File
@@ -1 +1 @@
The documentation is generated using doxygen (http://www.doxygen.org).
The documentation is generated using doxygen (http://www.doxygen.org).
+19 -19
View File
@@ -1,19 +1,19 @@
#ifndef JSON_AUTOLINK_H_INCLUDED
# define JSON_AUTOLINK_H_INCLUDED
# include "config.h"
# ifdef JSON_IN_CPPTL
# include <cpptl/cpptl_autolink.h>
# endif
# if !defined(JSON_NO_AUTOLINK) && !defined(JSON_DLL_BUILD) && !defined(JSON_IN_CPPTL)
# define CPPTL_AUTOLINK_NAME "json"
# undef CPPTL_AUTOLINK_DLL
# ifdef JSON_DLL
# define CPPTL_AUTOLINK_DLL
# endif
# include "autolink.h"
# endif
#endif // JSON_AUTOLINK_H_INCLUDED
#ifndef JSON_AUTOLINK_H_INCLUDED
# define JSON_AUTOLINK_H_INCLUDED
# include "config.h"
# ifdef JSON_IN_CPPTL
# include <cpptl/cpptl_autolink.h>
# endif
# if !defined(JSON_NO_AUTOLINK) && !defined(JSON_DLL_BUILD) && !defined(JSON_IN_CPPTL)
# define CPPTL_AUTOLINK_NAME "json"
# undef CPPTL_AUTOLINK_DLL
# ifdef JSON_DLL
# define CPPTL_AUTOLINK_DLL
# endif
# include "autolink.h"
# endif
#endif // JSON_AUTOLINK_H_INCLUDED
+43 -43
View File
@@ -1,43 +1,43 @@
#ifndef JSON_CONFIG_H_INCLUDED
# define JSON_CONFIG_H_INCLUDED
/// If defined, indicates that json library is embedded in CppTL library.
//# define JSON_IN_CPPTL 1
/// If defined, indicates that json may leverage CppTL library
//# define JSON_USE_CPPTL 1
/// If defined, indicates that cpptl vector based map should be used instead of std::map
/// as Value container.
//# define JSON_USE_CPPTL_SMALLMAP 1
/// If defined, indicates that Json specific container should be used
/// (hash table & simple deque container with customizable allocator).
/// THIS FEATURE IS STILL EXPERIMENTAL!
//# define JSON_VALUE_USE_INTERNAL_MAP 1
/// Force usage of standard new/malloc based allocator instead of memory pool based allocator.
/// The memory pools allocator used optimization (initializing Value and ValueInternalLink
/// as if it was a POD) that may cause some validation tool to report errors.
/// Only has effects if JSON_VALUE_USE_INTERNAL_MAP is defined.
//# define JSON_USE_SIMPLE_INTERNAL_ALLOCATOR 1
/// If defined, indicates that Json use exception to report invalid type manipulation
/// instead of C assert macro.
# define JSON_USE_EXCEPTION 1
# ifdef JSON_IN_CPPTL
# include <cpptl/config.h>
# ifndef JSON_USE_CPPTL
# define JSON_USE_CPPTL 1
# endif
# endif
# ifdef JSON_IN_CPPTL
# define JSON_API CPPTL_API
# elif defined(JSON_DLL_BUILD)
# define JSON_API __declspec(dllexport)
# elif defined(JSON_DLL)
# define JSON_API __declspec(dllimport)
# else
# define JSON_API
# endif
#endif // JSON_CONFIG_H_INCLUDED
#ifndef JSON_CONFIG_H_INCLUDED
# define JSON_CONFIG_H_INCLUDED
/// If defined, indicates that json library is embedded in CppTL library.
//# define JSON_IN_CPPTL 1
/// If defined, indicates that json may leverage CppTL library
//# define JSON_USE_CPPTL 1
/// If defined, indicates that cpptl vector based map should be used instead of std::map
/// as Value container.
//# define JSON_USE_CPPTL_SMALLMAP 1
/// If defined, indicates that Json specific container should be used
/// (hash table & simple deque container with customizable allocator).
/// THIS FEATURE IS STILL EXPERIMENTAL!
//# define JSON_VALUE_USE_INTERNAL_MAP 1
/// Force usage of standard new/malloc based allocator instead of memory pool based allocator.
/// The memory pools allocator used optimization (initializing Value and ValueInternalLink
/// as if it was a POD) that may cause some validation tool to report errors.
/// Only has effects if JSON_VALUE_USE_INTERNAL_MAP is defined.
//# define JSON_USE_SIMPLE_INTERNAL_ALLOCATOR 1
/// If defined, indicates that Json use exception to report invalid type manipulation
/// instead of C assert macro.
# define JSON_USE_EXCEPTION 1
# ifdef JSON_IN_CPPTL
# include <cpptl/config.h>
# ifndef JSON_USE_CPPTL
# define JSON_USE_CPPTL 1
# endif
# endif
# ifdef JSON_IN_CPPTL
# define JSON_API CPPTL_API
# elif defined(JSON_DLL_BUILD)
# define JSON_API __declspec(dllexport)
# elif defined(JSON_DLL)
# define JSON_API __declspec(dllimport)
# else
# define JSON_API
# endif
#endif // JSON_CONFIG_H_INCLUDED
+42 -42
View File
@@ -1,42 +1,42 @@
#ifndef CPPTL_JSON_FEATURES_H_INCLUDED
# define CPPTL_JSON_FEATURES_H_INCLUDED
# include "forwards.h"
namespace Json {
/** \brief Configuration passed to reader and writer.
* This configuration object can be used to force the Reader or Writer
* to behave in a standard conforming way.
*/
class JSON_API Features
{
public:
/** \brief A configuration that allows all features and assumes all strings are UTF-8.
* - C & C++ comments are allowed
* - Root object can be any JSON value
* - Assumes Value strings are encoded in UTF-8
*/
static Features all();
/** \brief A configuration that is strictly compatible with the JSON specification.
* - Comments are forbidden.
* - Root object must be either an array or an object value.
* - Assumes Value strings are encoded in UTF-8
*/
static Features strictMode();
/** \brief Initialize the configuration like JsonConfig::allFeatures;
*/
Features();
/// \c true if comments are allowed. Default: \c true.
bool allowComments_;
/// \c true if root must be either an array or an object value. Default: \c false.
bool strictRoot_;
};
} // namespace Json
#endif // CPPTL_JSON_FEATURES_H_INCLUDED
#ifndef CPPTL_JSON_FEATURES_H_INCLUDED
# define CPPTL_JSON_FEATURES_H_INCLUDED
# include "forwards.h"
namespace Json {
/** \brief Configuration passed to reader and writer.
* This configuration object can be used to force the Reader or Writer
* to behave in a standard conforming way.
*/
class JSON_API Features
{
public:
/** \brief A configuration that allows all features and assumes all strings are UTF-8.
* - C & C++ comments are allowed
* - Root object can be any JSON value
* - Assumes Value strings are encoded in UTF-8
*/
static Features all();
/** \brief A configuration that is strictly compatible with the JSON specification.
* - Comments are forbidden.
* - Root object must be either an array or an object value.
* - Assumes Value strings are encoded in UTF-8
*/
static Features strictMode();
/** \brief Initialize the configuration like JsonConfig::allFeatures;
*/
Features();
/// \c true if comments are allowed. Default: \c true.
bool allowComments_;
/// \c true if root must be either an array or an object value. Default: \c false.
bool strictRoot_;
};
} // namespace Json
#endif // CPPTL_JSON_FEATURES_H_INCLUDED
+39 -39
View File
@@ -1,39 +1,39 @@
#ifndef JSON_FORWARDS_H_INCLUDED
# define JSON_FORWARDS_H_INCLUDED
# include "config.h"
namespace Json {
// writer.h
class FastWriter;
class StyledWriter;
// reader.h
class Reader;
// features.h
class Features;
// value.h
typedef int Int;
typedef unsigned int UInt;
class StaticString;
class Path;
class PathArgument;
class Value;
class ValueIteratorBase;
class ValueIterator;
class ValueConstIterator;
#ifdef JSON_VALUE_USE_INTERNAL_MAP
class ValueAllocator;
class ValueMapAllocator;
class ValueInternalLink;
class ValueInternalArray;
class ValueInternalMap;
#endif // #ifdef JSON_VALUE_USE_INTERNAL_MAP
} // namespace Json
#endif // JSON_FORWARDS_H_INCLUDED
#ifndef JSON_FORWARDS_H_INCLUDED
# define JSON_FORWARDS_H_INCLUDED
# include "config.h"
namespace Json {
// writer.h
class FastWriter;
class StyledWriter;
// reader.h
class Reader;
// features.h
class Features;
// value.h
typedef int Int;
typedef unsigned int UInt;
class StaticString;
class Path;
class PathArgument;
class Value;
class ValueIteratorBase;
class ValueIterator;
class ValueConstIterator;
#ifdef JSON_VALUE_USE_INTERNAL_MAP
class ValueAllocator;
class ValueMapAllocator;
class ValueInternalLink;
class ValueInternalArray;
class ValueInternalMap;
#endif // #ifdef JSON_VALUE_USE_INTERNAL_MAP
} // namespace Json
#endif // JSON_FORWARDS_H_INCLUDED
+10 -10
View File
@@ -1,10 +1,10 @@
#ifndef JSON_JSON_H_INCLUDED
# define JSON_JSON_H_INCLUDED
# include "autolink.h"
# include "value.h"
# include "reader.h"
# include "writer.h"
# include "features.h"
#endif // JSON_JSON_H_INCLUDED
#ifndef JSON_JSON_H_INCLUDED
# define JSON_JSON_H_INCLUDED
# include "autolink.h"
# include "value.h"
# include "reader.h"
# include "writer.h"
# include "features.h"
#endif // JSON_JSON_H_INCLUDED
+196 -196
View File
@@ -1,196 +1,196 @@
#ifndef CPPTL_JSON_READER_H_INCLUDED
# define CPPTL_JSON_READER_H_INCLUDED
# include "features.h"
# include "value.h"
# include <deque>
# include <stack>
# include <string>
# include <iostream>
namespace Json {
/** \brief Unserialize a <a HREF="http://www.json.org">JSON</a> document into a Value.
*
*/
class JSON_API Reader
{
public:
typedef char Char;
typedef const Char *Location;
/** \brief Constructs a Reader allowing all features
* for parsing.
*/
Reader();
/** \brief Constructs a Reader allowing the specified feature set
* for parsing.
*/
Reader( const Features &features );
/** \brief Read a Value from a <a HREF="http://www.json.org">JSON</a> document.
* \param document UTF-8 encoded string containing the document to read.
* \param root [out] Contains the root value of the document if it was
* successfully parsed.
* \param collectComments \c true to collect comment and allow writing them back during
* serialization, \c false to discard comments.
* This parameter is ignored if Features::allowComments_
* is \c false.
* \return \c true if the document was successfully parsed, \c false if an error occurred.
*/
bool parse( const std::string &document,
Value &root,
bool collectComments = true );
/** \brief Read a Value from a <a HREF="http://www.json.org">JSON</a> document.
* \param document UTF-8 encoded string containing the document to read.
* \param root [out] Contains the root value of the document if it was
* successfully parsed.
* \param collectComments \c true to collect comment and allow writing them back during
* serialization, \c false to discard comments.
* This parameter is ignored if Features::allowComments_
* is \c false.
* \return \c true if the document was successfully parsed, \c false if an error occurred.
*/
bool parse( const char *beginDoc, const char *endDoc,
Value &root,
bool collectComments = true );
/// \brief Parse from input stream.
/// \see Json::operator>>(std::istream&, Json::Value&).
bool parse( std::istream &is,
Value &root,
bool collectComments = true );
/** \brief Returns a user friendly string that list errors in the parsed document.
* \return Formatted error message with the list of errors with their location in
* the parsed document. An empty string is returned if no error occurred
* during parsing.
*/
std::string getFormatedErrorMessages() const;
private:
enum TokenType
{
tokenEndOfStream = 0,
tokenObjectBegin,
tokenObjectEnd,
tokenArrayBegin,
tokenArrayEnd,
tokenString,
tokenNumber,
tokenTrue,
tokenFalse,
tokenNull,
tokenArraySeparator,
tokenMemberSeparator,
tokenComment,
tokenError
};
class Token
{
public:
TokenType type_;
Location start_;
Location end_;
};
class ErrorInfo
{
public:
Token token_;
std::string message_;
Location extra_;
};
typedef std::deque<ErrorInfo> Errors;
bool expectToken( TokenType type, Token &token, const char *message );
bool readToken( Token &token );
void skipSpaces();
bool match( Location pattern,
int patternLength );
bool readComment();
bool readCStyleComment();
bool readCppStyleComment();
bool readString();
void readNumber();
bool readValue();
bool readObject( Token &token );
bool readArray( Token &token );
bool decodeNumber( Token &token );
bool decodeString( Token &token );
bool decodeString( Token &token, std::string &decoded );
bool decodeDouble( Token &token );
bool decodeUnicodeCodePoint( Token &token,
Location &current,
Location end,
unsigned int &unicode );
bool decodeUnicodeEscapeSequence( Token &token,
Location &current,
Location end,
unsigned int &unicode );
bool addError( const std::string &message,
Token &token,
Location extra = 0 );
bool recoverFromError( TokenType skipUntilToken );
bool addErrorAndRecover( const std::string &message,
Token &token,
TokenType skipUntilToken );
void skipUntilSpace();
Value &currentValue();
Char getNextChar();
void getLocationLineAndColumn( Location location,
int &line,
int &column ) const;
std::string getLocationLineAndColumn( Location location ) const;
void addComment( Location begin,
Location end,
CommentPlacement placement );
void skipCommentTokens( Token &token );
typedef std::stack<Value *> Nodes;
Nodes nodes_;
Errors errors_;
std::string document_;
Location begin_;
Location end_;
Location current_;
Location lastValueEnd_;
Value *lastValue_;
std::string commentsBefore_;
Features features_;
bool collectComments_;
};
/** \brief Read from 'sin' into 'root'.
Always keep comments from the input JSON.
This can be used to read a file into a particular sub-object.
For example:
\code
Json::Value root;
cin >> root["dir"]["file"];
cout << root;
\endcode
Result:
\verbatim
{
"dir": {
"file": {
// The input stream JSON would be nested here.
}
}
}
\endverbatim
\throw std::exception on parse error.
\see Json::operator<<()
*/
std::istream& operator>>( std::istream&, Value& );
} // namespace Json
#endif // CPPTL_JSON_READER_H_INCLUDED
#ifndef CPPTL_JSON_READER_H_INCLUDED
# define CPPTL_JSON_READER_H_INCLUDED
# include "features.h"
# include "value.h"
# include <deque>
# include <stack>
# include <string>
# include <iostream>
namespace Json {
/** \brief Unserialize a <a HREF="http://www.json.org">JSON</a> document into a Value.
*
*/
class JSON_API Reader
{
public:
typedef char Char;
typedef const Char *Location;
/** \brief Constructs a Reader allowing all features
* for parsing.
*/
Reader();
/** \brief Constructs a Reader allowing the specified feature set
* for parsing.
*/
Reader( const Features &features );
/** \brief Read a Value from a <a HREF="http://www.json.org">JSON</a> document.
* \param document UTF-8 encoded string containing the document to read.
* \param root [out] Contains the root value of the document if it was
* successfully parsed.
* \param collectComments \c true to collect comment and allow writing them back during
* serialization, \c false to discard comments.
* This parameter is ignored if Features::allowComments_
* is \c false.
* \return \c true if the document was successfully parsed, \c false if an error occurred.
*/
bool parse( const std::string &document,
Value &root,
bool collectComments = true );
/** \brief Read a Value from a <a HREF="http://www.json.org">JSON</a> document.
* \param document UTF-8 encoded string containing the document to read.
* \param root [out] Contains the root value of the document if it was
* successfully parsed.
* \param collectComments \c true to collect comment and allow writing them back during
* serialization, \c false to discard comments.
* This parameter is ignored if Features::allowComments_
* is \c false.
* \return \c true if the document was successfully parsed, \c false if an error occurred.
*/
bool parse( const char *beginDoc, const char *endDoc,
Value &root,
bool collectComments = true );
/// \brief Parse from input stream.
/// \see Json::operator>>(std::istream&, Json::Value&).
bool parse( std::istream &is,
Value &root,
bool collectComments = true );
/** \brief Returns a user friendly string that list errors in the parsed document.
* \return Formatted error message with the list of errors with their location in
* the parsed document. An empty string is returned if no error occurred
* during parsing.
*/
std::string getFormatedErrorMessages() const;
private:
enum TokenType
{
tokenEndOfStream = 0,
tokenObjectBegin,
tokenObjectEnd,
tokenArrayBegin,
tokenArrayEnd,
tokenString,
tokenNumber,
tokenTrue,
tokenFalse,
tokenNull,
tokenArraySeparator,
tokenMemberSeparator,
tokenComment,
tokenError
};
class Token
{
public:
TokenType type_;
Location start_;
Location end_;
};
class ErrorInfo
{
public:
Token token_;
std::string message_;
Location extra_;
};
typedef std::deque<ErrorInfo> Errors;
bool expectToken( TokenType type, Token &token, const char *message );
bool readToken( Token &token );
void skipSpaces();
bool match( Location pattern,
int patternLength );
bool readComment();
bool readCStyleComment();
bool readCppStyleComment();
bool readString();
void readNumber();
bool readValue();
bool readObject( Token &token );
bool readArray( Token &token );
bool decodeNumber( Token &token );
bool decodeString( Token &token );
bool decodeString( Token &token, std::string &decoded );
bool decodeDouble( Token &token );
bool decodeUnicodeCodePoint( Token &token,
Location &current,
Location end,
unsigned int &unicode );
bool decodeUnicodeEscapeSequence( Token &token,
Location &current,
Location end,
unsigned int &unicode );
bool addError( const std::string &message,
Token &token,
Location extra = 0 );
bool recoverFromError( TokenType skipUntilToken );
bool addErrorAndRecover( const std::string &message,
Token &token,
TokenType skipUntilToken );
void skipUntilSpace();
Value &currentValue();
Char getNextChar();
void getLocationLineAndColumn( Location location,
int &line,
int &column ) const;
std::string getLocationLineAndColumn( Location location ) const;
void addComment( Location begin,
Location end,
CommentPlacement placement );
void skipCommentTokens( Token &token );
typedef std::stack<Value *> Nodes;
Nodes nodes_;
Errors errors_;
std::string document_;
Location begin_;
Location end_;
Location current_;
Location lastValueEnd_;
Value *lastValue_;
std::string commentsBefore_;
Features features_;
bool collectComments_;
};
/** \brief Read from 'sin' into 'root'.
Always keep comments from the input JSON.
This can be used to read a file into a particular sub-object.
For example:
\code
Json::Value root;
cin >> root["dir"]["file"];
cout << root;
\endcode
Result:
\verbatim
{
"dir": {
"file": {
// The input stream JSON would be nested here.
}
}
}
\endverbatim
\throw std::exception on parse error.
\see Json::operator<<()
*/
std::istream& operator>>( std::istream&, Value& );
} // namespace Json
#endif // CPPTL_JSON_READER_H_INCLUDED
File diff suppressed because it is too large Load Diff
+174 -174
View File
@@ -1,174 +1,174 @@
#ifndef JSON_WRITER_H_INCLUDED
# define JSON_WRITER_H_INCLUDED
# include "value.h"
# include <vector>
# include <string>
# include <iostream>
namespace Json {
class Value;
/** \brief Abstract class for writers.
*/
class JSON_API Writer
{
public:
virtual ~Writer();
virtual std::string write( const Value &root ) = 0;
};
/** \brief Outputs a Value in <a HREF="http://www.json.org">JSON</a> format without formatting (not human friendly).
*
* The JSON document is written in a single line. It is not intended for 'human' consumption,
* but may be usefull to support feature such as RPC where bandwith is limited.
* \sa Reader, Value
*/
class JSON_API FastWriter : public Writer
{
public:
FastWriter();
virtual ~FastWriter(){}
void enableYAMLCompatibility();
public: // overridden from Writer
virtual std::string write( const Value &root );
private:
void writeValue( const Value &value );
std::string document_;
bool yamlCompatiblityEnabled_;
};
/** \brief Writes a Value in <a HREF="http://www.json.org">JSON</a> format in a human friendly way.
*
* The rules for line break and indent are as follow:
* - Object value:
* - if empty then print {} without indent and line break
* - if not empty the print '{', line break & indent, print one value per line
* and then unindent and line break and print '}'.
* - Array value:
* - if empty then print [] without indent and line break
* - if the array contains no object value, empty array or some other value types,
* and all the values fit on one lines, then print the array on a single line.
* - otherwise, it the values do not fit on one line, or the array contains
* object or non empty array, then print one value per line.
*
* If the Value have comments then they are outputed according to their #CommentPlacement.
*
* \sa Reader, Value, Value::setComment()
*/
class JSON_API StyledWriter: public Writer
{
public:
StyledWriter();
virtual ~StyledWriter(){}
public: // overridden from Writer
/** \brief Serialize a Value in <a HREF="http://www.json.org">JSON</a> format.
* \param root Value to serialize.
* \return String containing the JSON document that represents the root value.
*/
virtual std::string write( const Value &root );
private:
void writeValue( const Value &value );
void writeArrayValue( const Value &value );
bool isMultineArray( const Value &value );
void pushValue( const std::string &value );
void writeIndent();
void writeWithIndent( const std::string &value );
void indent();
void unindent();
void writeCommentBeforeValue( const Value &root );
void writeCommentAfterValueOnSameLine( const Value &root );
bool hasCommentForValue( const Value &value );
static std::string normalizeEOL( const std::string &text );
typedef std::vector<std::string> ChildValues;
ChildValues childValues_;
std::string document_;
std::string indentString_;
int rightMargin_;
int indentSize_;
bool addChildValues_;
};
/** \brief Writes a Value in <a HREF="http://www.json.org">JSON</a> format in a human friendly way,
to a stream rather than to a string.
*
* The rules for line break and indent are as follow:
* - Object value:
* - if empty then print {} without indent and line break
* - if not empty the print '{', line break & indent, print one value per line
* and then unindent and line break and print '}'.
* - Array value:
* - if empty then print [] without indent and line break
* - if the array contains no object value, empty array or some other value types,
* and all the values fit on one lines, then print the array on a single line.
* - otherwise, it the values do not fit on one line, or the array contains
* object or non empty array, then print one value per line.
*
* If the Value have comments then they are outputed according to their #CommentPlacement.
*
* \param indentation Each level will be indented by this amount extra.
* \sa Reader, Value, Value::setComment()
*/
class JSON_API StyledStreamWriter
{
public:
StyledStreamWriter( std::string indentation="\t" );
~StyledStreamWriter(){}
public:
/** \brief Serialize a Value in <a HREF="http://www.json.org">JSON</a> format.
* \param out Stream to write to. (Can be ostringstream, e.g.)
* \param root Value to serialize.
* \note There is no point in deriving from Writer, since write() should not return a value.
*/
void write( std::ostream &out, const Value &root );
private:
void writeValue( const Value &value );
void writeArrayValue( const Value &value );
bool isMultineArray( const Value &value );
void pushValue( const std::string &value );
void writeIndent();
void writeWithIndent( const std::string &value );
void indent();
void unindent();
void writeCommentBeforeValue( const Value &root );
void writeCommentAfterValueOnSameLine( const Value &root );
bool hasCommentForValue( const Value &value );
static std::string normalizeEOL( const std::string &text );
typedef std::vector<std::string> ChildValues;
ChildValues childValues_;
std::ostream* document_;
std::string indentString_;
int rightMargin_;
std::string indentation_;
bool addChildValues_;
};
std::string JSON_API valueToString( Int value );
std::string JSON_API valueToString( UInt value );
std::string JSON_API valueToString( double value );
std::string JSON_API valueToString( bool value );
std::string JSON_API valueToQuotedString( const char *value );
/// \brief Output using the StyledStreamWriter.
/// \see Json::operator>>()
std::ostream& operator<<( std::ostream&, const Value &root );
} // namespace Json
#endif // JSON_WRITER_H_INCLUDED
#ifndef JSON_WRITER_H_INCLUDED
# define JSON_WRITER_H_INCLUDED
# include "value.h"
# include <vector>
# include <string>
# include <iostream>
namespace Json {
class Value;
/** \brief Abstract class for writers.
*/
class JSON_API Writer
{
public:
virtual ~Writer();
virtual std::string write( const Value &root ) = 0;
};
/** \brief Outputs a Value in <a HREF="http://www.json.org">JSON</a> format without formatting (not human friendly).
*
* The JSON document is written in a single line. It is not intended for 'human' consumption,
* but may be usefull to support feature such as RPC where bandwith is limited.
* \sa Reader, Value
*/
class JSON_API FastWriter : public Writer
{
public:
FastWriter();
virtual ~FastWriter(){}
void enableYAMLCompatibility();
public: // overridden from Writer
virtual std::string write( const Value &root );
private:
void writeValue( const Value &value );
std::string document_;
bool yamlCompatiblityEnabled_;
};
/** \brief Writes a Value in <a HREF="http://www.json.org">JSON</a> format in a human friendly way.
*
* The rules for line break and indent are as follow:
* - Object value:
* - if empty then print {} without indent and line break
* - if not empty the print '{', line break & indent, print one value per line
* and then unindent and line break and print '}'.
* - Array value:
* - if empty then print [] without indent and line break
* - if the array contains no object value, empty array or some other value types,
* and all the values fit on one lines, then print the array on a single line.
* - otherwise, it the values do not fit on one line, or the array contains
* object or non empty array, then print one value per line.
*
* If the Value have comments then they are outputed according to their #CommentPlacement.
*
* \sa Reader, Value, Value::setComment()
*/
class JSON_API StyledWriter: public Writer
{
public:
StyledWriter();
virtual ~StyledWriter(){}
public: // overridden from Writer
/** \brief Serialize a Value in <a HREF="http://www.json.org">JSON</a> format.
* \param root Value to serialize.
* \return String containing the JSON document that represents the root value.
*/
virtual std::string write( const Value &root );
private:
void writeValue( const Value &value );
void writeArrayValue( const Value &value );
bool isMultineArray( const Value &value );
void pushValue( const std::string &value );
void writeIndent();
void writeWithIndent( const std::string &value );
void indent();
void unindent();
void writeCommentBeforeValue( const Value &root );
void writeCommentAfterValueOnSameLine( const Value &root );
bool hasCommentForValue( const Value &value );
static std::string normalizeEOL( const std::string &text );
typedef std::vector<std::string> ChildValues;
ChildValues childValues_;
std::string document_;
std::string indentString_;
int rightMargin_;
int indentSize_;
bool addChildValues_;
};
/** \brief Writes a Value in <a HREF="http://www.json.org">JSON</a> format in a human friendly way,
to a stream rather than to a string.
*
* The rules for line break and indent are as follow:
* - Object value:
* - if empty then print {} without indent and line break
* - if not empty the print '{', line break & indent, print one value per line
* and then unindent and line break and print '}'.
* - Array value:
* - if empty then print [] without indent and line break
* - if the array contains no object value, empty array or some other value types,
* and all the values fit on one lines, then print the array on a single line.
* - otherwise, it the values do not fit on one line, or the array contains
* object or non empty array, then print one value per line.
*
* If the Value have comments then they are outputed according to their #CommentPlacement.
*
* \param indentation Each level will be indented by this amount extra.
* \sa Reader, Value, Value::setComment()
*/
class JSON_API StyledStreamWriter
{
public:
StyledStreamWriter( std::string indentation="\t" );
~StyledStreamWriter(){}
public:
/** \brief Serialize a Value in <a HREF="http://www.json.org">JSON</a> format.
* \param out Stream to write to. (Can be ostringstream, e.g.)
* \param root Value to serialize.
* \note There is no point in deriving from Writer, since write() should not return a value.
*/
void write( std::ostream &out, const Value &root );
private:
void writeValue( const Value &value );
void writeArrayValue( const Value &value );
bool isMultineArray( const Value &value );
void pushValue( const std::string &value );
void writeIndent();
void writeWithIndent( const std::string &value );
void indent();
void unindent();
void writeCommentBeforeValue( const Value &root );
void writeCommentAfterValueOnSameLine( const Value &root );
bool hasCommentForValue( const Value &value );
static std::string normalizeEOL( const std::string &text );
typedef std::vector<std::string> ChildValues;
ChildValues childValues_;
std::ostream* document_;
std::string indentString_;
int rightMargin_;
std::string indentation_;
bool addChildValues_;
};
std::string JSON_API valueToString( Int value );
std::string JSON_API valueToString( UInt value );
std::string JSON_API valueToString( double value );
std::string JSON_API valueToString( bool value );
std::string JSON_API valueToQuotedString( const char *value );
/// \brief Output using the StyledStreamWriter.
/// \see Json::operator>>()
std::ostream& operator<<( std::ostream&, const Value &root );
} // namespace Json
#endif // JSON_WRITER_H_INCLUDED
+125 -125
View File
@@ -1,125 +1,125 @@
#ifndef JSONCPP_BATCHALLOCATOR_H_INCLUDED
# define JSONCPP_BATCHALLOCATOR_H_INCLUDED
# include <stdlib.h>
# include <assert.h>
# ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION
namespace Json {
/* Fast memory allocator.
*
* This memory allocator allocates memory for a batch of object (specified by
* the page size, the number of object in each page).
*
* It does not allow the destruction of a single object. All the allocated objects
* can be destroyed at once. The memory can be either released or reused for future
* allocation.
*
* The in-place new operator must be used to construct the object using the pointer
* returned by allocate.
*/
template<typename AllocatedType
,const unsigned int objectPerAllocation>
class BatchAllocator
{
public:
typedef AllocatedType Type;
BatchAllocator( unsigned int objectsPerPage = 255 )
: freeHead_( 0 )
, objectsPerPage_( objectsPerPage )
{
// printf( "Size: %d => %s\n", sizeof(AllocatedType), typeid(AllocatedType).name() );
assert( sizeof(AllocatedType) * objectPerAllocation >= sizeof(AllocatedType *) ); // We must be able to store a slist in the object free space.
assert( objectsPerPage >= 16 );
batches_ = allocateBatch( 0 ); // allocated a dummy page
currentBatch_ = batches_;
}
~BatchAllocator()
{
for ( BatchInfo *batch = batches_; batch; )
{
BatchInfo *nextBatch = batch->next_;
free( batch );
batch = nextBatch;
}
}
/// allocate space for an array of objectPerAllocation object.
/// @warning it is the responsability of the caller to call objects constructors.
AllocatedType *allocate()
{
if ( freeHead_ ) // returns node from free list.
{
AllocatedType *object = freeHead_;
freeHead_ = *(AllocatedType **)object;
return object;
}
if ( currentBatch_->used_ == currentBatch_->end_ )
{
currentBatch_ = currentBatch_->next_;
while ( currentBatch_ && currentBatch_->used_ == currentBatch_->end_ )
currentBatch_ = currentBatch_->next_;
if ( !currentBatch_ ) // no free batch found, allocate a new one
{
currentBatch_ = allocateBatch( objectsPerPage_ );
currentBatch_->next_ = batches_; // insert at the head of the list
batches_ = currentBatch_;
}
}
AllocatedType *allocated = currentBatch_->used_;
currentBatch_->used_ += objectPerAllocation;
return allocated;
}
/// Release the object.
/// @warning it is the responsability of the caller to actually destruct the object.
void release( AllocatedType *object )
{
assert( object != 0 );
*(AllocatedType **)object = freeHead_;
freeHead_ = object;
}
private:
struct BatchInfo
{
BatchInfo *next_;
AllocatedType *used_;
AllocatedType *end_;
AllocatedType buffer_[objectPerAllocation];
};
// disabled copy constructor and assignement operator.
BatchAllocator( const BatchAllocator & );
void operator =( const BatchAllocator &);
static BatchInfo *allocateBatch( unsigned int objectsPerPage )
{
const unsigned int mallocSize = sizeof(BatchInfo) - sizeof(AllocatedType)* objectPerAllocation
+ sizeof(AllocatedType) * objectPerAllocation * objectsPerPage;
BatchInfo *batch = static_cast<BatchInfo*>( malloc( mallocSize ) );
batch->next_ = 0;
batch->used_ = batch->buffer_;
batch->end_ = batch->buffer_ + objectsPerPage;
return batch;
}
BatchInfo *batches_;
BatchInfo *currentBatch_;
/// Head of a single linked list within the allocated space of freeed object
AllocatedType *freeHead_;
unsigned int objectsPerPage_;
};
} // namespace Json
# endif // ifndef JSONCPP_DOC_INCLUDE_IMPLEMENTATION
#endif // JSONCPP_BATCHALLOCATOR_H_INCLUDED
#ifndef JSONCPP_BATCHALLOCATOR_H_INCLUDED
# define JSONCPP_BATCHALLOCATOR_H_INCLUDED
# include <stdlib.h>
# include <assert.h>
# ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION
namespace Json {
/* Fast memory allocator.
*
* This memory allocator allocates memory for a batch of object (specified by
* the page size, the number of object in each page).
*
* It does not allow the destruction of a single object. All the allocated objects
* can be destroyed at once. The memory can be either released or reused for future
* allocation.
*
* The in-place new operator must be used to construct the object using the pointer
* returned by allocate.
*/
template<typename AllocatedType
,const unsigned int objectPerAllocation>
class BatchAllocator
{
public:
typedef AllocatedType Type;
BatchAllocator( unsigned int objectsPerPage = 255 )
: freeHead_( 0 )
, objectsPerPage_( objectsPerPage )
{
// printf( "Size: %d => %s\n", sizeof(AllocatedType), typeid(AllocatedType).name() );
assert( sizeof(AllocatedType) * objectPerAllocation >= sizeof(AllocatedType *) ); // We must be able to store a slist in the object free space.
assert( objectsPerPage >= 16 );
batches_ = allocateBatch( 0 ); // allocated a dummy page
currentBatch_ = batches_;
}
~BatchAllocator()
{
for ( BatchInfo *batch = batches_; batch; )
{
BatchInfo *nextBatch = batch->next_;
free( batch );
batch = nextBatch;
}
}
/// allocate space for an array of objectPerAllocation object.
/// @warning it is the responsability of the caller to call objects constructors.
AllocatedType *allocate()
{
if ( freeHead_ ) // returns node from free list.
{
AllocatedType *object = freeHead_;
freeHead_ = *(AllocatedType **)object;
return object;
}
if ( currentBatch_->used_ == currentBatch_->end_ )
{
currentBatch_ = currentBatch_->next_;
while ( currentBatch_ && currentBatch_->used_ == currentBatch_->end_ )
currentBatch_ = currentBatch_->next_;
if ( !currentBatch_ ) // no free batch found, allocate a new one
{
currentBatch_ = allocateBatch( objectsPerPage_ );
currentBatch_->next_ = batches_; // insert at the head of the list
batches_ = currentBatch_;
}
}
AllocatedType *allocated = currentBatch_->used_;
currentBatch_->used_ += objectPerAllocation;
return allocated;
}
/// Release the object.
/// @warning it is the responsability of the caller to actually destruct the object.
void release( AllocatedType *object )
{
assert( object != 0 );
*(AllocatedType **)object = freeHead_;
freeHead_ = object;
}
private:
struct BatchInfo
{
BatchInfo *next_;
AllocatedType *used_;
AllocatedType *end_;
AllocatedType buffer_[objectPerAllocation];
};
// disabled copy constructor and assignement operator.
BatchAllocator( const BatchAllocator & );
void operator =( const BatchAllocator &);
static BatchInfo *allocateBatch( unsigned int objectsPerPage )
{
const unsigned int mallocSize = sizeof(BatchInfo) - sizeof(AllocatedType)* objectPerAllocation
+ sizeof(AllocatedType) * objectPerAllocation * objectsPerPage;
BatchInfo *batch = static_cast<BatchInfo*>( malloc( mallocSize ) );
batch->next_ = 0;
batch->used_ = batch->buffer_;
batch->end_ = batch->buffer_ + objectsPerPage;
return batch;
}
BatchInfo *batches_;
BatchInfo *currentBatch_;
/// Head of a single linked list within the allocated space of freeed object
AllocatedType *freeHead_;
unsigned int objectsPerPage_;
};
} // namespace Json
# endif // ifndef JSONCPP_DOC_INCLUDE_IMPLEMENTATION
#endif // JSONCPP_BATCHALLOCATOR_H_INCLUDED
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+6398 -6398
View File
File diff suppressed because it is too large Load Diff