all. I've been banging my head up against this one for a while... I'm trying to put together an example of basically perlembed + perlcall and more or less "borrowed" it from evpsgi. The problem is that it grows about 1MB in size for every 1000 iterations. This isn't the greatest situation to be in when running in a long lived process (which is the use case that I'm working with).
As the title states, if I run with valgrind it reports that there are no leaks possible. I ran with --trace-malloc=yes and it appears that free is only ever called at the end in a big batch of calls. I understand that this may be perl's MO but it would be nice if it at least re-used the memory and didn't grow until the OS killed off the process.
The entry for sv_2mortal mentions something about the buffer being available to be "stolen" but I've peppered the code with calls to sv_2mortal but there was no change.
Without further ado, here is the code. Please forgive the cargo cultishness of it. Thanks in advance!
/*
*
* cc `perl -MExtUtils::Embed -e ccopts -e ldopts` -Wall -ggdb test_perl_2.c -o test_perl_2
*
* # test.psgi
* use strict;
* use warnings;
* my $app = sub {
* return [ 200, [ test => 1 ], [ sprintf( "%d: Hello!!! from %s\n", $$, __FILE__ ) ] ];
* };
*
*/
#include <stdio.h>
#include <EXTERN.h> /* from the Perl distribution */
#include <perl.h> /* from the Perl distribution */
static PerlInterpreter *perlinterp; /*** The Perl interpreter ***/
static SV *app;
void do_stuff( void );
SV * get_stuff( void );
SV * call_stuff( SV * );
EXTERN_C void xs_init( pTHX );
EXTERN_C void boot_DynaLoader (pTHX_ CV* cv);
EXTERN_C void xs_init( pTHX ) {
char *file = __FILE__;
dXSUB_SYS;
/* DynaLoader is a special case */
newXS("DynaLoader::boot_DynaLoader", boot_DynaLoader, file);
}
int main( int argc, char **argv, char **env ) {
char code[ 1024 ];
char psgi[] = "test.psgi";
char *embedding[] = { "", "-e", "0" };
PERL_SYS_INIT3( &argc, &argv, &env );
perlinterp = perl_alloc();
PERL_SET_CONTEXT( perlinterp );
perl_construct( perlinterp );
perl_parse( perlinterp, xs_init, 3, embedding, (char **)NULL );
PL_exit_flags |= PERL_EXIT_DESTRUCT_END;
sprintf( code, "do '%s' or die $#", psgi );
app = eval_pv( code, TRUE ); /* croak_on_error */
do_stuff();
PL_perl_destruct_level = 1;
perl_destruct( perlinterp );
perl_free( perlinterp );
PERL_SYS_TERM();
return 0;
}
void do_stuff( void ) {
int body_lastindex, i, count;
AV *response_av, *body_av;
SV *stuff_sv, *response_sv, *status, *tmp_body_sv, *body_sv;
// count = 10000;
count = 10;
while( count-- ) {
ENTER;
SAVETMPS;
stuff_sv = get_stuff();
response_sv = call_stuff( stuff_sv );
if(
NULL == response_sv ||
! SvROK( response_sv ) ||
SvTYPE( SvRV( response_sv ) ) != SVt_PVAV
) {
printf( "NULL == response_sv\n" );
goto CLIENT_END;
}
response_av = (AV *)SvRV( response_sv );
status = *av_fetch( response_av, 0, 0 );
printf( "status = %ld\n", (long)SvIV( status ) );
body_av = (AV *)SvRV( *av_fetch( response_av, 2, 0 ) );
body_sv = newSV( 0 );
body_lastindex = av_len( body_av );
for( i = 0; i <= body_lastindex; i++ ) {
tmp_body_sv = (SV *)*av_fetch( body_av, i, 0 );
if( SvOK( tmp_body_sv ) ) {
sv_catsv( body_sv, tmp_body_sv );
}
}
printf( "body_sv = %s\n", SvPV_nolen( body_sv ) );
CLIENT_END:
FREETMPS;
LEAVE;
}
}
SV * get_stuff( void ) {
HV *stuff_hv;
// stuff_hv = (HV *)sv_2mortal((SV *)newHV());
stuff_hv = newHV();
if( NULL == hv_store( stuff_hv, "SCRIPT_NAME", strlen( "SCRIPT_NAME" ), newSVpv( "", 0 ), 0 ) ) {
croak( "hv_store( 'SCRIPT_NAME' )" );
}
if( NULL == hv_store( stuff_hv, "REQUEST_METHOD", strlen( "REQUEST_METHOD" ), newSVpv( "GET", 3 ), 0 ) ) {
croak( "hv_store( 'REQUEST_METHOD' )" );
}
if( NULL == hv_store( stuff_hv, "REQUEST_URI", strlen( "REQUEST_URI" ), newSVpv( "/abc?def", 8 ), 0 ) ) {
croak( "hv_store( 'REQUEST_URI' )" );
}
if( NULL == hv_store( stuff_hv, "PATH_INFO", strlen( "PATH_INFO" ), newSVpv( "/abc", 4 ), 0 ) ) {
croak( "hv_store( 'PATH_INFO' )" );
}
if( NULL == hv_store( stuff_hv, "QUERY_STRING", strlen( "QUERY_STRING" ), newSVpv( "def", 3 ), 0 ) ) {
croak( "hv_store( 'QUERY_STRING' )" );
}
return newRV_inc( (SV *)stuff_hv );
}
SV * call_stuff( SV *stuff_sv ) {
SV *response_sv;
int count;
// printf( "REQUEST_URI = %s\n", SvPV_nolen( *hv_fetch( (HV *)SvRV( stuff_sv ), "REQUEST_URI", strlen( "REQUEST_URI" ), 0 ) ) );
dSP;
ENTER;
SAVETMPS;
PUSHMARK( SP );
XPUSHs( stuff_sv ); // stuff_sv is not mortal.
PUTBACK;
count = call_sv( app, G_EVAL | G_SCALAR | G_KEEPERR );
SPAGAIN;
if( SvTRUE( ERRSV ) ) {
response_sv = NULL;
fprintf( stderr, "FATAL: %s", SvPV_nolen( ERRSV ) );
/* CLEAR_ERRSV() is only available 5.8.9 or later */
if( SvMAGICAL( ERRSV ) ) {
mg_free( ERRSV );
mg_clear( ERRSV );
}
sv_setpvn_mg( ERRSV, "", 0 );
POPs; // causes "warning: value computed is not used"
}
else if( count > 0 ) {
response_sv = POPs; // is this mortal?
SvREFCNT_inc( response_sv );
} else {
response_sv = NULL;
}
PUTBACK;
FREETMPS;
LEAVE;
return response_sv;
}
You don't free anything! You get a scalar from Perl and you create two yourself, but none of them are getting freed.
Leak 1
You have:
HV *stuff_hv;
stuff_hv = newHV();
return newRV_inc( (SV *)stuff_hv );
Two problems with that:
You're creating an HV with a refcnt of 2.
Change newRV_inc to newRV_noinc.
You never free it (or return it from a XS func as a mortal).
Use SvREFCNT_dec( stuff_sv ) when you're done with it, perhaps after the call to call_stuff.
Leak 2
You have:
body_sv = newSV( 0 );
Again, there's no corresponding freeing of that scalar. You need
SvREFCNT_dec( body_sv );
after the printf.
Leak 3
You have:
response_sv = POPs; // is this mortal?
SvREFCNT_inc( response_sv );
It doesn't really matter if it's mortal or not. You need to claim ownership of it in case it is, so the inc is appropriate. But you must later release it when you're done with it.
SvREFCNT_dec( response_sv );
Related
int copy( char *from, char *to ) {
int fd_from, fd_to, rbytes, wbytes;
char buff[256];
if( ( fd_from = open( from, O_RDONLY ) ) == -1 )
{ perror( “open from” ); return( - 1 ); }
if( ( fd_to = open( to, O_WRONLY | O_CREAT, 0664 ) ) == -1 )
{ perror( “open to” ); return( -1 ); }
if( ( rbytes = read( fd_from, buff, 256 ) ) == -1 )
{ perror( “read 1” ); return( -1 ); }
while( rbytes > 0 ) {
if( ( wbytes = write( fd_to, buff, rbytes ) ) == -1 )
{ perror( “write” ); return( -1 ); }
if( wbytes != rbytes )
{ fprintf( stderr, “bad write\n” ); return( -1 ); }
if( ( rbytes = read( fd_from, buff, 256 ) ) == -1 )
{ perror( “read 2” ); return( -1 ); }
}
close( fd_from ); close( fd_to ); return( 0 );
}
why is there a loop that checks if rbytes>0?
I understand the reasons for 2 if's statments inside the loop but not the last one, why do we have to read the file again?
why is there a loop that checks if rbytes>0?
Because every read operation only reads up to 256 bytes, yet most files are larger than that. The loop continues until the input file is fully read, at which point read will return 0, and the loop will terminate.
How to extract resources for sys-file? I believe that exe, dll and sys-files have same headers. Is that correct?
I don't understand what shall I do with VirtualAddress and Size which I get for resource table.
#include <stdio.h>
#include <windows.h>
#include <string.h>
void main()
{
FILE *file = fopen( "example.sys", "r" );
IMAGE_DOS_HEADER dos_header;
IMAGE_NT_HEADERS nt_header;
IMAGE_DATA_DIRECTORY data_directory;
char *data;
if( file != NULL )
{
fseek( file, 0, SEEK_SET );
fread( &dos_header, sizeof( dos_header ), 1, file );
if( dos_header.e_magic != IMAGE_DOS_SIGNATURE )
return;
fseek( file, dos_header.e_lfanew, SEEK_SET );
fread( &nt_header, sizeof( nt_header ), 1, file );
if( nt_header.Signature != IMAGE_NT_SIGNATURE )
return;
data_directory = nt_header.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE];
data = malloc( data_directory.Size + 1 );
memset( data, 0, data_directory.Size + 1 );
fseek( file, data_directory.VirtualAddress, SEEK_SET ); // <- ????
fread( data, data_directory.Size, 1, file );
free( data );
fclose( file );
}
}
VirtualAddress is actually the relative virtual address (RVA) of the data structure.
For example, if this structure is for import symbols, this field contains the RVA of the IMAGE_IMPORT_DESCRIPTOR array.
isize contains the size in bytes of the data structure referred to by VirtualAddress.
Take a look at THIS link. It is a good explanation on how to go deep into a win32 assembly.
I finally found code example which answered my question - PEDump.
Using it I made this sample:
#include <stdio.h>
#include <windows.h>
#include <string.h>
#define MakePtr( cast, ptr, addValue ) (cast)( (DWORD)(ptr) + (DWORD)(addValue))
#define RESOURCE_ADDRESS( pdr, o ) ((PUCHAR) (pdr + 1) + (o))
typedef struct tag_VS_VERSIONINFO
{
USHORT wLength; // 00 length of entire version resource
USHORT wValueLength; // 02 length of fixed file info, if any
USHORT wType; // 04 type of resource (1 = text, 0 = binary)
WCHAR szKey[17]; // 06 key -- VS_VERSION_INFO + padding byte
VS_FIXEDFILEINFO Value; // 28 fixed information about this file (13 dwords)
}
VS_VERSIONINFO, *PVS_VERSIONINFO; // 5C
PIMAGE_SECTION_HEADER GetEnclosingSectionHeader(DWORD rva,
PIMAGE_NT_HEADERS pNTHeader)
{
PIMAGE_SECTION_HEADER section = IMAGE_FIRST_SECTION(pNTHeader);
unsigned i;
for ( i=0; i < pNTHeader->FileHeader.NumberOfSections; i++, section++ )
{
// Is the RVA within this section?
if ( (rva >= section->VirtualAddress) &&
(rva < (section->VirtualAddress + section->Misc.VirtualSize)))
return section;
}
return 0;
}
LPVOID GetPtrFromRVA( DWORD rva, PIMAGE_NT_HEADERS pNTHeader, DWORD imageBase )
{
PIMAGE_SECTION_HEADER pSectionHdr;
INT delta;
pSectionHdr = GetEnclosingSectionHeader( rva, pNTHeader );
if ( !pSectionHdr )
return 0;
delta = (INT)(pSectionHdr->VirtualAddress-pSectionHdr->PointerToRawData);
return (PVOID) ( imageBase + rva - delta );
}
void main()
{
unsigned int index;
PIMAGE_DOS_HEADER dos_header;
PIMAGE_NT_HEADERS nt_header;
PIMAGE_DATA_DIRECTORY data_directory;
PIMAGE_RESOURCE_DIRECTORY resources;
PIMAGE_RESOURCE_DIRECTORY_ENTRY listItem;
PIMAGE_RESOURCE_DIRECTORY child;
PIMAGE_RESOURCE_DIRECTORY_ENTRY version;
PIMAGE_RESOURCE_DATA_ENTRY data_entry;
PVS_VERSIONINFO version_info;
HANDLE hFile;
HANDLE hFileMapping;
LPVOID lpFileBase;
hFile = CreateFile( L"samples.sys",
GENERIC_READ,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
0
);
if ( hFile == INVALID_HANDLE_VALUE )
return;
hFileMapping = CreateFileMapping( hFile, NULL, PAGE_READONLY, 0, 0, NULL );
if ( hFileMapping == 0 )
{
CloseHandle(hFile);
return;
}
lpFileBase = MapViewOfFile( hFileMapping, FILE_MAP_READ, 0, 0, 0 );
if ( lpFileBase == 0 )
{
CloseHandle(hFileMapping);
CloseHandle(hFile);
return;
}
dos_header = MakePtr( PIMAGE_DOS_HEADER, lpFileBase, 0 );
if( dos_header->e_magic != IMAGE_DOS_SIGNATURE )
return;
nt_header = MakePtr( PIMAGE_NT_HEADERS, lpFileBase, dos_header->e_lfanew );
if( nt_header->Signature != IMAGE_NT_SIGNATURE )
return;
data_directory = &nt_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE];
resources = ( PIMAGE_RESOURCE_DIRECTORY )GetPtrFromRVA( data_directory->VirtualAddress, nt_header, ( DWORD )lpFileBase );
listItem = ( PIMAGE_RESOURCE_DIRECTORY_ENTRY )( resources + 1 );
for( index = 0; index < resources->NumberOfIdEntries; index++ )
{
if( listItem->Id == ( WORD )RT_VERSION )
{
if( listItem->DataIsDirectory )
{
child = ( PIMAGE_RESOURCE_DIRECTORY )( ( listItem->OffsetToData & 0x7FFFFFFF ) + (DWORD)resources );
version = ( PIMAGE_RESOURCE_DIRECTORY_ENTRY )( child + 1 );
if( version->DataIsDirectory )
{
child = ( PIMAGE_RESOURCE_DIRECTORY )( ( version->OffsetToData & 0x7FFFFFFF ) + (DWORD)resources );
version = ( PIMAGE_RESOURCE_DIRECTORY_ENTRY )( child + 1 );
data_entry = ( PIMAGE_RESOURCE_DATA_ENTRY )( ( version->OffsetToData & 0x7FFFFFFF ) + (DWORD)resources );
version_info = ( PVS_VERSIONINFO )GetPtrFromRVA( data_entry->OffsetToData, nt_header, ( DWORD )lpFileBase );
}
}
}
listItem += 1;
}
}
Most interesting part here is function GetPtrFromRVA which shall be used to convert VirtualAddress to offset from the beginning of the file.
I am trying to make an application which uses AES 256 Encryption. Unfortunately i can't get it work. Maybe i didn't understand the crpytographic logic fully.
So it is working, but as far as i understand the hash contains the password. But if i change the password the output is the same. So it seems that CryptEncrypt ignoes the Hash.
Could someone please help me?
Thanks in advance!
Here is my code:
if ( !CryptAcquireContext( &hProv, NULL, MS_ENH_RSA_AES_PROV, PROV_RSA_AES, CRYPT_VERIFYCONTEXT ) )
{
printf( "\nCryptAcquireContext failed %d", GetLastError() );
return;
}
if ( !CryptImportKey( hProv, ( const LPBYTE )&keyBlob, sizeof( keyBlob ), 0, CRYPT_EXPORTABLE, &hPubKey ) )
{
printf( "\nCryptImportKey failed %d", GetLastError() );
return;
}
if ( !CryptCreateHash( hProv, CALG_SHA_256, 0, 0, &hHash ) )
{
printf( "Error %x during CryptCreateHash!\n", GetLastError() );
return;
}
if ( !CryptHashData( hHash, ( PBYTE )wszPassword, cbPassword, 0 ) )
{
printf( "Error %x during CryptHashData!\n", GetLastError() );
return;
}
//if ( !CryptDeriveKey( hProv, CALG_AES_256, hHash, CRYPT_EXPORTABLE, &hKey ) )//hKey
//{
// printf( "Error %x during CryptDeriveKey!\n", GetLastError() );
// return;
//}
if ( !CryptSetKeyParam( hPubKey, KP_IV, ivData, 0 ) )
{
printf( "\nCryptSetKeyParam failed %d", GetLastError() );
return;
}
DWORD size = ( DWORD )strlen( StringToEncrypt ) / sizeof( char );
//printf( "\nLength of string to encrypt = %d\n\n", size );
if ( !CryptEncrypt( hPubKey, hHash, TRUE, 0, ( LPBYTE )StringToEncrypt, &size, ( size / 16 + 1 ) * 16 ) )
{
printf( "\nCryptEncrypt failed %d", GetLastError() );
int a = GetLastError();
switch ( a )
{
case NTE_BAD_HASH_STATE: printf( "NTE_BAD_HASH_STATE" ); break;
case NTE_BAD_HASH: printf( "NTE_BAD_HASH" ); break;
}
return;
}
The "password" - usually known as the key - is in hPubKey. The hHash is for generating a hash at the same time as the encryption is done. Look here for more information.
I read h.264 frames from webcamera and capture audio from microphone. I need to stream live video to ffserver. During debug I read video from ffserver using ffmpeg with following command:
ffmpeg -i http://127.0.0.1:12345/robot.avi -vcodec copy -acodec copy out.avi
My video in output file is slightly accelerated. If I add a audio stream it is accelerated several times. Sometimes there is no audio in the output file.
Here is my code for encoding audio:
#include "v_audio_encoder.h"
extern "C" {
#include <libavcodec/avcodec.h>
}
#include <cassert>
struct VAudioEncoder::Private
{
AVCodec *m_codec;
AVCodecContext *m_context;
std::vector<uint8_t> m_outBuffer;
};
VAudioEncoder::VAudioEncoder( int sampleRate, int bitRate )
{
d = new Private( );
d->m_codec = avcodec_find_encoder( CODEC_ID_MP3 );
assert( d->m_codec );
d->m_context = avcodec_alloc_context3( d->m_codec );
// put sample parameters
d->m_context->channels = 2;
d->m_context->bit_rate = bitRate;
d->m_context->sample_rate = sampleRate;
d->m_context->sample_fmt = AV_SAMPLE_FMT_S16;
strcpy( d->m_context->codec_name, "libmp3lame" );
// open it
int res = avcodec_open2( d->m_context, d->m_codec, 0 );
assert( res >= 0 );
d->m_outBuffer.resize( d->m_context->frame_size );
}
VAudioEncoder::~VAudioEncoder( )
{
avcodec_close( d->m_context );
av_free( d->m_context );
delete d;
}
void VAudioEncoder::encode( const std::vector<uint32_t>& samples, std::vector<uint8_t>& outbuf )
{
assert( (int)samples.size( ) == d->m_context->frame_size );
int outSize = avcodec_encode_audio( d->m_context, d->m_outBuffer.data( ),
d->m_outBuffer.size( ), reinterpret_cast<const short*>( samples.data( ) ) );
if( outSize ) {
outbuf.resize( outSize );
memcpy( outbuf.data( ), d->m_outBuffer.data( ), outSize );
}
else
outbuf.clear( );
}
int VAudioEncoder::getFrameSize( ) const
{
return d->m_context->frame_size;
}
Here is my code for streaming video:
#include "v_out_video_stream.h"
extern "C" {
#include <libavformat/avformat.h>
#include <libavutil/opt.h>
#include <libavutil/avstring.h>
#include <libavformat/avio.h>
}
#include <stdexcept>
#include <cassert>
struct VStatticRegistrar
{
VStatticRegistrar( )
{
av_register_all( );
avformat_network_init( );
}
};
VStatticRegistrar __registrar;
struct VOutVideoStream::Private
{
AVFormatContext * m_context;
int m_videoStreamIndex;
int m_audioStreamIndex;
int m_videoBitrate;
int m_width;
int m_height;
int m_fps;
int m_bitrate;
bool m_waitKeyFrame;
};
VOutVideoStream::VOutVideoStream( int width, int height, int fps, int bitrate )
{
d = new Private( );
d->m_width = width;
d->m_height = height;
d->m_fps = fps;
d->m_context = 0;
d->m_videoStreamIndex = -1;
d->m_audioStreamIndex = -1;
d->m_bitrate = bitrate;
d->m_waitKeyFrame = true;
}
bool VOutVideoStream::connectToServer( const std::string& uri )
{
assert( ! d->m_context );
// initalize the AV context
d->m_context = avformat_alloc_context();
if( !d->m_context )
return false;
// get the output format
d->m_context->oformat = av_guess_format( "ffm", NULL, NULL );
if( ! d->m_context->oformat )
return false;
strcpy( d->m_context->filename, uri.c_str( ) );
// add an H.264 stream
AVStream *stream = avformat_new_stream( d->m_context, NULL );
if ( ! stream )
return false;
// initalize codec
AVCodecContext* codec = stream->codec;
if( d->m_context->oformat->flags & AVFMT_GLOBALHEADER )
codec->flags |= CODEC_FLAG_GLOBAL_HEADER;
codec->codec_id = CODEC_ID_H264;
codec->codec_type = AVMEDIA_TYPE_VIDEO;
strcpy( codec->codec_name, "libx264" );
// codec->codec_tag = ( unsigned('4') << 24 ) + (unsigned('6') << 16 ) + ( unsigned('2') << 8 ) + 'H';
codec->width = d->m_width;
codec->height = d->m_height;
codec->time_base.den = d->m_fps;
codec->time_base.num = 1;
codec->bit_rate = d->m_bitrate;
d->m_videoStreamIndex = stream->index;
// add an MP3 stream
stream = avformat_new_stream( d->m_context, NULL );
if ( ! stream )
return false;
// initalize codec
codec = stream->codec;
if( d->m_context->oformat->flags & AVFMT_GLOBALHEADER )
codec->flags |= CODEC_FLAG_GLOBAL_HEADER;
codec->codec_id = CODEC_ID_MP3;
codec->codec_type = AVMEDIA_TYPE_AUDIO;
strcpy( codec->codec_name, "libmp3lame" );
codec->sample_fmt = AV_SAMPLE_FMT_S16;
codec->channels = 2;
codec->bit_rate = 64000;
codec->sample_rate = 44100;
d->m_audioStreamIndex = stream->index;
// try to open the stream
if( avio_open( &d->m_context->pb, d->m_context->filename, AVIO_FLAG_WRITE ) < 0 )
return false;
// write the header
return avformat_write_header( d->m_context, NULL ) == 0;
}
void VOutVideoStream::disconnect( )
{
assert( d->m_context );
avio_close( d->m_context->pb );
avformat_free_context( d->m_context );
d->m_context = 0;
}
VOutVideoStream::~VOutVideoStream( )
{
if( d->m_context )
disconnect( );
delete d;
}
int VOutVideoStream::getVopType( const std::vector<uint8_t>& image )
{
if( image.size( ) < 6 )
return -1;
unsigned char *b = (unsigned char*)image.data( );
// Verify NAL marker
if( b[ 0 ] || b[ 1 ] || 0x01 != b[ 2 ] ) {
++b;
if ( b[ 0 ] || b[ 1 ] || 0x01 != b[ 2 ] )
return -1;
}
b += 3;
// Verify VOP id
if( 0xb6 == *b ) {
++b;
return ( *b & 0xc0 ) >> 6;
}
switch( *b ) {
case 0x65: return 0;
case 0x61: return 1;
case 0x01: return 2;
}
return -1;
}
bool VOutVideoStream::sendVideoFrame( std::vector<uint8_t>& image )
{
// Init packet
AVPacket pkt;
av_init_packet( &pkt );
pkt.flags |= ( 0 >= getVopType( image ) ) ? AV_PKT_FLAG_KEY : 0;
// Wait for key frame
if ( d->m_waitKeyFrame ) {
if( pkt.flags & AV_PKT_FLAG_KEY )
d->m_waitKeyFrame = false;
else
return true;
}
pkt.stream_index = d->m_videoStreamIndex;
pkt.data = image.data( );
pkt.size = image.size( );
pkt.pts = pkt.dts = AV_NOPTS_VALUE;
return av_write_frame( d->m_context, &pkt ) >= 0;
}
bool VOutVideoStream::sendAudioFrame( std::vector<uint8_t>& audio )
{
// Init packet
AVPacket pkt;
av_init_packet( &pkt );
pkt.stream_index = d->m_audioStreamIndex;
pkt.data = audio.data( );
pkt.size = audio.size( );
pkt.pts = pkt.dts = AV_NOPTS_VALUE;
return av_write_frame( d->m_context, &pkt ) >= 0;
}
Here is how I use it:
BOOST_AUTO_TEST_CASE(testSendingVideo)
{
const int framesToGrab = 90000;
VOutVideoStream stream( VIDEO_WIDTH, VIDEO_HEIGHT, FPS, VIDEO_BITRATE );
if( stream.connectToServer( URI ) ) {
VAudioEncoder audioEncoder( AUDIO_SAMPLE_RATE, AUDIO_BIT_RATE );
VAudioCapture microphone( MICROPHONE_NAME, AUDIO_SAMPLE_RATE, audioEncoder.getFrameSize( ) );
VLogitecCamera camera( VIDEO_WIDTH, VIDEO_HEIGHT );
BOOST_REQUIRE( camera.open( CAMERA_PORT ) );
BOOST_REQUIRE( camera.startCapturing( ) );
std::vector<uint8_t> image, encodedAudio;
std::vector<uint32_t> voice;
boost::system_time startTime;
int delta;
for( int i = 0; i < framesToGrab; ++i ) {
startTime = boost::posix_time::microsec_clock::universal_time( );
BOOST_REQUIRE( camera.read( image ) );
BOOST_REQUIRE( microphone.read( voice ) );
audioEncoder.encode( voice, encodedAudio );
BOOST_REQUIRE( stream.sendVideoFrame( image ) );
BOOST_REQUIRE( stream.sendAudioFrame( encodedAudio ) );
delta = ( boost::posix_time::microsec_clock::universal_time( ) - startTime ).total_milliseconds( );
if( delta < 1000 / FPS )
boost::thread::sleep( startTime + boost::posix_time::milliseconds( 1000 / FPS - delta ) );
}
BOOST_REQUIRE( camera.stopCapturing( ) );
BOOST_REQUIRE( camera.close( ) );
}
else
std::cout << "failed to connect to server" << std::endl;
}
I think my problem is in PTS and DTS. Can anyone help me?
I have a RichEdit control in my simple application that I wish to simulate a console-like display with. I want to be able to have a buffer of x number of lines (say, 300) and whenever a line is added, I would like to also remove the oldest (top) line if the new line exceeded the threshold x. I would also like it to automatically scroll to the bottom to display the newest line when added.
I've been using SetWindowText with some success, however it occurs to me that there is likely a more efficient method of appending text to the end and removing text from the beginning without having to replace all of it every time. Is this true, and, if so, how might I go about it?
Also, how might I make it automatically scroll to the bottom of the window when new text is added?
This is using the Win32 API from C, and I'm not using the MFC version of RichEdit (just using the vanilla Win32 API on XP and Vista).
To add text, you set the selection to the end of the text (EM_SETSEL), then replace the selection with the new text (EM_REPLACESEL).
To scroll to the bottom, you can send it a WM_VSCROLL with SB_BOTTOM.
I send you some methods of sample class cConsole:
class cConsole {
private:
//-------------------
int lines;
int max_lines; // Init it with your choise ( 300 )
//-------------------
char* buf;
int buf_size;
//-------------------
int CheckMemory( int size );
void NewLine( int new_lines );
void InternalPrint( char* msg, int size );
public:
HWND hWin;
void Print( char* msg ); // Add text data through this methods
void Print( char* msg, int size );
cConsole( );
~cConsole( );
};
int cConsole::CheckMemory( int size ) {
int rv = 1;
if( size + 16 >= buf_size ) {
int new_buf_size = size + 1024;
char* new_buf = ( char* )realloc( buf, new_buf_size );
if( new_buf != NULL ) {
buf = new_buf;
buf_size = new_buf_size;
} else {
rv = 0;
}
}
return rv;
}
void cConsole::NewLine( int new_lines ) {
int rem_lines = ( new_lines + lines + 1 ) - max_lines;
if( rem_lines <= 0 ) {
lines += new_lines;
} else {
int sel = SendMessage( hWin, EM_LINEINDEX, rem_lines, 0 );
SendMessage( hWin, EM_SETSEL, 0, (LPARAM)sel );
SendMessage( hWin, EM_REPLACESEL, FALSE, (LPARAM)"" );
SendMessage( hWin, WM_VSCROLL, SB_BOTTOM, NULL );
lines = max_lines - 1;
}
}
void cConsole::Print( char* msg ) { InternalPrint( msg, -1 ); }
void cConsole::Print( char* msg, int size ) { if( size < 0 ) size = 0; InternalPrint( msg, size ); }
void cConsole::InternalPrint( char* msg, int size ) {
int s, t = 0;
int new_lines = 0;
char* tb;
// msg only mode
if( size == -1 ) size = 0x7fffffff;
if( msg != NULL && size && CheckMemory( t ) ) {
for( s = 0; msg[ s ] && ( s < size ); s++ ) {
if( msg[ s ] == '\r' ) continue;
if( !CheckMemory( t ) ) break;
if( msg[ s ] == '\n' ) {
++new_lines;
buf[ t++ ] = '\r';
}
buf[ t++ ] = msg[ s ];
}
buf[ t ] = '\0';
}
if( t && msg != NULL ) {
tb = buf;
} else {
++new_lines;
tb = "\r\n";
}
SendMessage( hWin, EM_SETSEL, (WPARAM)-2, (LPARAM)-1 );
SendMessage( hWin, EM_REPLACESEL, FALSE, (LPARAM)tb );
SendMessage( hWin, WM_VSCROLL, SB_BOTTOM, NULL );
if( new_lines ) NewLine( new_lines );
}
Built your own class and check this!