Extract resources from sys-file - c

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.

Related

perlembed/perlcall example unbounded memory growth - valgrind says no leaks possible

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 );

transmit video and audio via RTSP

I need to implement server that allows to connect to two types of clients. The first type must stream live video and audio to server. The second type must stream this video from server. I've choosen h.264 encoding for video, vorbis ogg encoding for audio. I want to use RTSP protocol for streaming video from the first type of clients to server. I've implemented clients part using "libavformat" from ffmpeg.My code is given below.
#include "v_out_video_stream.h"
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
#include <libavformat/avformat.h>
#include <libavutil/opt.h>
#include <libavutil/avstring.h>
#include <libavformat/avio.h>
#ifdef __cplusplus
}
#endif
#include <stdexcept>
struct VStatticRegistrar
{
VStatticRegistrar( )
{
av_register_all( );
avformat_network_init( );
}
};
VStatticRegistrar __registrar;
struct VOutVideoStream::Private
{
AVFormatContext * m_context;
int m_audioStreamIndex;
int m_videoStreamIndex;
int m_videoBitrate;
int m_width;
int m_height;
int m_fps;
int m_audioSamplerate;
};
VOutVideoStream::VOutVideoStream( int videoBitrate, int width, int height, int fps, int audioSamplerate )
{
d = new Private( );
d->m_videoBitrate = videoBitrate;
d->m_width = width;
d->m_height = height;
d->m_fps = fps;
d->m_audioSamplerate = audioSamplerate;
d->m_context = 0;
d->m_audioStreamIndex = -1;
d->m_videoStreamIndex = -1;
}
bool VOutVideoStream::connectToServer( const std::string& rtp_address, int rtp_port )
{
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( "rtsp", NULL, NULL );
if( ! d->m_context->oformat )
return false;
// try to open the RTSP stream
snprintf( d->m_context->filename, sizeof( d->m_context->filename ), "rtsp://%s:%d", rtp_address.c_str(), rtp_port );
if( avio_open( &d->m_context->pb, d->m_context->filename, AVIO_FLAG_WRITE ) < 0 )
return false;
// 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;
//codec->bit_rate = d->m_videoBitrate;
codec->width = d->m_width;
codec->height = d->m_height;
codec->time_base.den = d->m_fps;
codec->time_base.num = 1;
d->m_audioStreamIndex = stream->index;
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_VORBIS;
codec->codec_type = AVMEDIA_TYPE_AUDIO;
codec->sample_fmt = AV_SAMPLE_FMT_S16;
codec->channels = 2;
codec->bit_rate = d->m_audioSamplerate * codec->channels * 16;
codec->sample_rate = d->m_audioSamplerate;
d->m_videoStreamIndex = stream->index;
// 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;
}
bool VOutVideoStream::send( VNetworkAbstractionLayer& nal )
{
AVPacket p;
av_init_packet( &p );
p.data = nal.getPayload( );
p.size = nal.getSize( );
p.stream_index = nal.getType( ) == VNetworkAbstractionLayer::AUDIO_PACKET ? d->m_audioStreamIndex :
d->m_videoStreamIndex;
return av_write_frame( d->m_context, &p ) >= 0;
}
VNetworkAbstractionLayer is defined so:
#ifndef _V_NETWORK_ABSTRACTION_LAYER_H_
#define _V_NETWORK_ABSTRACTION_LAYER_H_
#include <cs/v_cs_global.h>
#include <stdint.h>
#include <cstring>
#include <boost/noncopyable.hpp>
#include <boost/enable_shared_from_this.hpp>
class VNetworkAbstractionLayer : public boost::enable_shared_from_this<VNetworkAbstractionLayer>,
private boost::noncopyable
{
public:
enum PacketType
{
AUDIO_PACKET,
VIDEO_PACKET
};
~VNetworkAbstractionLayer( ) {
delete[] m_payload;
}
static VNetworkAbstractionLayerPtr factory( int size, const uint8_t* payload, PacketType type ) {
return VNetworkAbstractionLayerPtr( new VNetworkAbstractionLayer( size, payload, type ) );
}
uint8_t* getPayload( ) {
return m_payload;
}
int getSize( ) const {
return m_size;
}
PacketType getType( ) const {
return m_type;
}
private:
VNetworkAbstractionLayer( int size, const uint8_t* payload, PacketType type ) :
m_size( size ),
m_payload( new uint8_t[ size ] ),
m_type( type )
{
memcpy( m_payload, payload, size );
}
int m_size;
uint8_t *m_payload;
PacketType m_type;
};
#endif // _V_NETWORK_ABSTRACTION_LAYER_H_
Now I need to implement server. But I have not found any 'listen' method in libavformat. Can anyone explain me how to implement RTSP server. May be I can use any other library?
I would go with GStreamer on this. There are many examples out there.
It is pretty complex to code a RTSP/RTCP/RTP stack from scratch. You can have a look at the live555 library that implement such a stack in c++. It works well with ffmpeg/libav
You can also use https://net7mma.codeplex.com/ as your server!
You can use VLC as your streaming server.

how to stream h.264 video with mp3 audio using libavcodec?

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?

Different result everytime it is called

Why is it that the following code does not print the same value each time it is run?
Is there something that I overlooked? Thanks.
#include <windows.h>
#include <stdio.h>
#include <winhttp.h>
#pragma comment (lib, "winhttp")
int main(void)
{
DWORD dwSize = 0;
DWORD dwDownloaded = 0;
LPSTR pszOutBuffer;
BOOL bResults = FALSE;
HINTERNET hSession = NULL,
hConnect = NULL,
hRequest = NULL;
// Use WinHttpOpen to obtain a session handle.
hSession = WinHttpOpen( L"WinHTTP Example/1.0", WINHTTP_ACCESS_TYPE_NO_PROXY, WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, 0 );
// Specify an HTTP server.
if( hSession )
hConnect = WinHttpConnect( hSession, L"www.htc.com",
INTERNET_DEFAULT_HTTP_PORT, 0 );
// Create an HTTP request handle.
if( hConnect )
hRequest = WinHttpOpenRequest( hConnect, L"GET", L"uploadedImages/Common/Shared_Image/Icons/HTC_HD2_Location.jpg",
NULL, WINHTTP_NO_REFERER,
WINHTTP_DEFAULT_ACCEPT_TYPES,
0 );
// Send a request.
if( hRequest )
bResults = WinHttpSendRequest( hRequest,
WINHTTP_NO_ADDITIONAL_HEADERS, 0,
WINHTTP_NO_REQUEST_DATA, 0,
0, 0 );
// End the request.
if( bResults )
bResults = WinHttpReceiveResponse( hRequest, NULL );
// Keep checking for data until there is nothing left.
if( bResults )
{
do
{
// Check for available data.
dwSize = 0;
if( !WinHttpQueryDataAvailable( hRequest, &dwSize ) )
printf( "Error %u in WinHttpQueryDataAvailable.\n",
GetLastError( ) );
// Allocate space for the buffer.
pszOutBuffer = new char[dwSize+1];
if( !pszOutBuffer )
{
printf( "Out of memory\n" );
dwSize=0;
}
else
{
// Read the data.
ZeroMemory( pszOutBuffer, dwSize+1 );
if( !WinHttpReadData( hRequest, (LPVOID)pszOutBuffer,
dwSize, &dwDownloaded ) )
printf( "Error %u in WinHttpReadData.\n", GetLastError( ) );
else
printf( "%s", pszOutBuffer );
// Free the memory allocated to the buffer.
delete [] pszOutBuffer;
}
} while( dwSize > 0 );
}
// Report any errors.
if( !bResults )
printf( "Error %d has occurred.\n", GetLastError( ) );
// Close any open handles.
if( hRequest ) WinHttpCloseHandle( hRequest );
if( hConnect ) WinHttpCloseHandle( hConnect );
if( hSession ) WinHttpCloseHandle( hSession );
return 0;
}
You are printing the content of a .jpg file as a C string. It isn't a string, it won't be zero-terminated correctly. You'll get some kind of rendition of the bytes in the .jpg, followed by a random number of characters. Until it blunders into a zero somewhere. Apparently quickly enough to prevent your program crashing.

How to use a RichEdit control like a console with the Win32 API?

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!

Resources