seekg() failing mysteriously - c++

I have a 2884765579 bytes file. This is double checked with this function, that returns that number:
size_t GetSize() {
const size_t current_position = mFile.tellg();
mFile.seekg(0, std::ios::end);
const size_t ret = mFile.tellg();
mFile.seekg(current_position);
return ret;
}
I then do:
mFile.seekg(pos, std::ios::beg);
// pos = 2883426827, which is < than the file size, 2884765579
This sets the failbit. errno is not changed. What steps can I take to troubleshoot this?
I am absolutely sure that:
The file size is really 2884765579
pos is really 2884765579
The failbit is not set before .seekg()
The failbit is set right after .seekg() and no other calls are made in between
The file is opened with the binary flag
EDIT: in case someone runs into the same problem.. Use this code I wrote (works on windows only) and many less headaches for you:
class BinaryIFile
{
public:
BinaryIFile(const string& path) : mPath(path), mFileSize(0) {
mFile = open(path.c_str(), O_RDONLY | O_BINARY);
if (mFile == -1)
FATAL(format("Cannot open %s: %s") % path.c_str() % strerror(errno));
}
~BinaryIFile() {
if (mFile != -1)
close(mFile);
}
string GetPath() const { return mPath; }
int64 GetSize() {
if (mFileSize)
return mFileSize;
const int64 current_position = _telli64(mFile);
_lseeki64(mFile, 0, SEEK_END);
mFileSize = _telli64(mFile);
_lseeki64(mFile, current_position, SEEK_SET);
return mFileSize;
}
int64 Read64() { return _Read<int64>(); }
int32 Read32() { return _Read<int32>(); }
int16 Read16() { return _Read<int16>(); }
int8 Read8() { return _Read<int8>(); }
float ReadFloat() { return _Read<float>(); }
double ReadDouble() { return _Read<double>(); }
void Skip(int64 bytes) { _lseeki64(mFile, bytes, SEEK_CUR); }
void Seek(int64 pos) { _lseeki64(mFile, pos, SEEK_SET); }
int64 Tell() { return _telli64(mFile); }
template <class T>
T Read() { return _Read<T>(); }
void Read(char *to, size_t size) {
const int ret = read(mFile, (void *)to, size);
if ((int)size != ret)
FATAL(format("Read error: attempted to read %d bytes, read() returned %d, errno: %s [we are at offset %d, file size is %d]") % size % ret % strerror(errno) % Tell() % GetSize());
}
template <class T>
BinaryIFile& operator>>(T& val) { val = _Read<T>(); return *this; }
private:
const string mPath;
int mFile;
int64 mFileSize;
template <class T>
T _Read() { T ret; if (sizeof(ret) != read(mFile, (void *)&ret, sizeof(ret))) FATAL("Read error"); return ret; }
};

You can seekg before a given position, so pos is signed. Try it with files of size 0x7fffffff and 0x80ffffff and see if the latter triggers the problem, that's my guess.

Related

SymFromAddr result is false in Release environment

pdb file exists and works normally in Debug mode, but the problem occurs only in the Release version.
It is a function that prints the call stack. How can I solve it?
One of the strange things when debugging was that the address was different in Relese version and Debug mode.
std::string SymbolLookup::GetSymbolString(void* address) const{
if (address == nullptr)
{
return "";
}
DWORD displacement = 0;
DWORD addr = reinterpret_cast<DWORD>(address);
SymbolBuffer symbol;
char buffer[kStrBufferSize] = { 0, };
IMAGEHLP_LINE line;
line.SizeOfStruct = sizeof(IMAGEHLP_LINE);
SymFromAddr(handle_, addr, 0, &symbol);
DWORD Temp = GetLastError();
BOOL ret = SymGetLineFromAddr(handle_, addr, &displacement, &line);
if (ret)
{
sprintf_s(buffer, kStrBufferSize, "%s(%d) : %s",
line.FileName, line.LineNumber, symbol.Name);
}
else
{
sprintf_s(buffer, kStrBufferSize, "No line info : %s", symbol.Name);
}
return std::string(buffer);
}
void log_callstack()
{
SymbolLookup lookup;
CallStack stack;
for (size_t i = 0; i < stack.GetCount(); ++i)
{
const string& str = lookup.GetSymbolString(stack[i]);
print_log(str.c_str());
}
}
class SymbolLookup
{
public:
SymbolLookup() : handle_(GetCurrentProcess())
{
SymInitialize(handle_, nullptr, TRUE);
SymSetOptions(SYMOPT_LOAD_LINES);
}
std::string GetSymbolString(void* address) const;
private:
const static size_t kStrBufferSize = 1024U;
private:
HANDLE handle_;
};
class CallStack
{
public:
static const size_t kMaxStackDepth = 24U;
public:
CallStack()
{
count_ = CaptureStackBackTrace(0, kMaxStackDepth, addresses_, &hash_);
}
void* operator[] (const size_t index) const { return addresses_[index]; }
ULONG GetHash() const { return hash_; }
size_t GetCount() const { return count_; }
private:
void* addresses_[kMaxStackDepth];
ULONG hash_;
size_t count_;
};
I found that the addresses value obtained through CaptureStackBackTrace is different when run with f5 and when run with Relese executable.
GetLastError() value is 487

Saving struct to clipboard in C++

I have this structure in my C++ code:
struct sData
{
DWORD Number;
int CurrentNumber;
bool GameOver;
};
I need to save it to Clipboard as a structure from one process. And from other process I need to load it again as the structure. I can do it easy with Cstrings/strings but not with structures. What do you suggest to me?
This is my method for setting Cstring to Clipboard:
bool SetText(CString text)
{
CString source;
source = text;
//put your text in source
if (OpenClipboard(NULL))
{
HGLOBAL clipbuffer;
char * buffer;
EmptyClipboard();
clipbuffer = GlobalAlloc(GMEM_DDESHARE, source.GetLength() + 1);
buffer = (char*)GlobalLock(clipbuffer);
strcpy(buffer, LPCSTR(source));
GlobalUnlock(clipbuffer);
SetClipboardData(CF_TEXT, clipbuffer);
CloseClipboard();
return true;
}
else
{
return false;
}
}
And this is getter:
std::string GetText(void) const
{
return (const char*)GetClipboardData(CF_TEXT);
}
You need to register your own clipboard format, then you can store the struct data as-is.
static UINT CF_MYSTRUCTDATA = RegisterClipboardFormat(TEXT("MyStructData"));
#pragma pack(push, 1)
struct sData
{
DWORD Number;
int CurrentNumber;
bool GameOver;
};
#pragma pack(pop)
bool SetData(const sData &data)
{
if (CF_MYSTRUCTDATA == 0)
return false;
bool bOK = false;
if (OpenClipboard(NULL))
{
if (EmptyClipboard())
{
HGLOBAL clipbuffer = GlobalAlloc(GMEM_MOVEABLE, sizeof(sData));
if (clipbuffer)
{
sData *buffer = (sData*) GlobalLock(clipbuffer);
if (buffer)
{
*buffer = data;
GlobalUnlock(clipbuffer);
bOK = SetClipboardData(CF_MYSTRUCTDATA, clipbuffer);
}
if (!bOK)
GlobalFree(clipbuffer);
}
}
CloseClipboard();
}
return bOK;
}
bool GetData(sData &data) const
{
if (CF_MYSTRUCTDATA == 0)
return false;
bool bOk = false;
if (OpenClipboard(NULL))
{
HANDLE clipbuffer = GetClipboardData(CF_MYSTRUCTDATA);
if (clipbuffer)
{
sData *buffer = (sData*) GlobalLock(clipbuffer);
if (buffer)
{
data = *buffer;
GlobalUnlock(clipbuffer);
bOK = true;
}
}
CloseClipboard();
}
return bOK;
}
Alternatively, using some C++ RAII wrappers:
struct Clipboard
{
Clipboard(HWND hWnd = NULL)
{
if (!OpenClipboard(hWnd))
throw std::runtime_error("Error opening clipboard");
}
~Clipboard()
{
CloseClipboard();
}
void Empty()
{
if (!EmptyClipboard())
throw std::runtime_error("Error emptying clipboard");
}
template<typename T>
struct DataBuffer
{
HGLOBAL _hmem;
bool _free;
struct Lock
{
DataBuffer& _buffer;
T* _data;
Lock(DataBuffer &buffer)
: _buffer(buffer), _locked(false)
{
_data = (T*) GlobalLock(_buffer.Get());
if (!_data)
throw std::runtime_error("Error locking memory");
}
~Lock()
{
GlobalUnlock(_buffer.Get());
}
T& Data() { return *_data; }
};
DataBuffer(const T &data)
: _hmem(NULL), _free(true)
{
_hmem = GlobalAlloc(GMEM_MOVEABLE, sizeof(T));
if (!_hmem)
throw std::runtime_error("Error allocating memory");
Lock(*this).Data() = data;
}
DataBuffer(HGLOBAL hmem)
: _hmem(mem), _free(false)
{
if (GlobalSize(_hmem)) < sizeof(T))
throw std::runtime_error("Bad memory size");
}
~DataBuffer()
{
if ((_hmem) && (_free))
GlobalFree(_hmem);
}
HGLOBAL Release()
{
HGLOBAL tmp = _hmem;
_hmem = NULL;
return tmp;
}
HGLOBAL Get()
{
return _hmem;
}
void Copy(T &data)
{
data = Lock(*this).Data();
}
};
template<typename T>
void SetData(UINT format, const T &data)
{
DataBuffer<T> buffer(data);
if (!SetClipboardData(format, buffer.Get()))
throw std::runtime_error("Error setting clipboard data");
buffer.Release();
}
template<typename T>
void GetData(UINT format, T &data)
{
DataBuffer<T> buffer(GetClipboardData(format));
if (!buffer.Get())
throw std::runtime_error("Error getting clipboard data");
buffer.Copy(data);
}
};
bool SetData(const sData &data)
{
if (CF_MYSTRUCTDATA != 0)
{
try
{
Clipboard clipbrd;
clipbrd.Empty();
clipbrd.SetData(CF_MYSTRUCTDATA, data);
return true;
}
catch (const std::runtime_error&)
{
}
}
return false;
}
bool GetData(sData &data) const
{
if (CF_MYSTRUCTDATA != 0)
{
try
{
Clipboard clipbrd;
clipbrd.GetData(CF_MYSTRUCTDATA, data);
return true;
}
catch (const std::runtime_error&)
{
}
}
return false;
}

Using Opus with PortAudio

I'm having trouble for using opus with Port audio.
I need to read data audio from a stream using PortAudio, encoding data, decoding data and writing data. If I just read and write, everything works well. But when encoding and decoding, all I can hear is snow with my voice in background.
Here a part of my code:
I/O stream header:
#define NUM_CHANNELS (2)
#define PA_SAMPLE_TYPE paInt24
#define SAMPLE_RATE (48000)
#define FRAMES_PER_BUFFER (1024)
#define SAMPLE_SIZE (3)
#define FRAME_SIZE (960)
class SoundSystem
{
private:
PaStream *_stream;
int _readBufferSize;
PaStreamParameters _inputParam;
PaStreamParameters _outputParam;
unsigned char *_readBuffer;
public:
SoundSystem();
~SoundSystem();
// Init Stream
bool initPa();
bool openStream();
bool startStream();
bool initStream();
// Init params stream
bool initParams() const;
bool initInputParams();
bool initOutputParams();
bool initParams();
// I/O
bool writeOnStream(unsigned cha\
r *buff);
bool readFromStream();
// Utils
void cleanReadBuffer();
int getReadBufferSize() const;
unsigned char *getReadBuffer() const;
};
I/O stream .cpp:
SoundSystem::SoundSystem()
{
_stream = NULL;
_readBufferSize = FRAMES_PER_BUFFER * NUM_CHANNELS * SAMPLE_SIZE;
_readBuffer= new unsigned char [_readBufferSize];
}
SoundSystem::~SoundSystem()
{
}
bool SoundSystem::initPa()
{
if ((Pa_Initialize()) != paNoError)
return (false);
return (true);
}
bool SoundSystem::openStream()
{
if ((Pa_OpenStream(&_stream, &_inputParam, &_outputParam, SAMPLE_RATE,
FRAMES_PER_BUFFER, paClipOff, NULL, NULL)) != paNoError)
return (false);
return (true);
}
bool SoundSystem::startStream()
{
if ((Pa_StartStream(_stream)) != paNoError)
return (false);
return (true);
}
bool SoundSystem::initStream()
{
if ((openStream()) == false)
std::cerr << "can not open stream" << std::endl;
if ((startStream()) == false)
std::cerr << "cannot start stream" <<std::endl;
return (true);
}
bool SoundSystem::initParams()
{
if ((initPa()) == false)
std::cerr << "can not ijnit PA" << std::endl;
initInputParams();
initOutputParams();
return (true);
}
bool SoundSystem::initInputParams()
{
if ((_inputParam.device = Pa_GetDefaultInputDevice()) == paNoDevice)
return (false);
_inputParam.channelCount = 2;
_inputParam.sampleFormat = PA_SAMPLE_TYPE;
_inputParam.suggestedLatency = Pa_GetDeviceInfo(_inputParam.device)->defaultLowInputLatency;
_inputParam.hostApiSpecificStreamInfo = NULL;
return (true);
}
bool SoundSystem::initOutputParams()
{
if ((_outputParam.device = Pa_GetDefaultInputDevice()) == paNoDevice)
return (false);
_outputParam.channelCount = 2;
_outputParam.sampleFormat = PA_SAMPLE_TYPE;
_outputParam.suggestedLatency = Pa_GetDeviceInfo(_outputParam.device)->defaultLowInputLatency;
_outputParam.hostApiSpecificStreamInfo = NULL;
return (true);
}
bool SoundSystem::writeOnStream(unsigned char *buff)
{
if ((Pa_WriteStream(_stream, buff, FRAMES_PER_BUFFER)) != paNoError)
{
std::cout << "FAIL WRITE" <<std::endl;
return (false);
}
return (true);
}
bool SoundSystem::readFromStream()
{
if ((Pa_ReadStream(_stream, _readBuffer, FRAMES_PER_BUFFER)) != paNoError)
return (false);
return (true);
}
void SoundSystem::cleanReadBuffer()
{
for (int i = 0; i != _readBufferSize; i++)
_readBuffer[i] = 0;
}
int SoundSystem::getReadBufferSize() const
{enter code here
return (_readBufferSize);
}
unsigned char* SoundSystem::getReadBuffer() const { return (_readBuffer); }
Encode header:
#define FRAME_SIZE (960)
#define SAMPLE_RATE (48000)
#define CHANNELS (2)
#define APPLICATION OPUS_APPLICATION_VOIP
#define MAX_FRAME_SIZE (6*960)
class EncoderSystem
{
private:
OpusEncoder *_encode;
OpusDecoder *_decode;
opus_int16 _in[FRAME_SIZE*CHANNELS];
opus_int16 _out[MAX_FRAME_SIZE*CHANNELS];
int _nbBytes;
public:
EncoderSystem();
~EncoderSystem();
bool encoderCreate();
bool decoderCreate();
unsigned char* encode(unsigned char *, int);
unsigned char* decode(unsigned char *, int);
int getEncodeLen() const;
};
Encode .cpp:
EncoderSystem::EncoderSystem()
{
}
EncoderSystem::~EncoderSystem()
{
}
bool EncoderSystem::encoderCreate()
{
int error;
if ((_encode = opus_encoder_create(SAMPLE_RATE, CHANNELS, OPUS_APPLICATION_VOIP, &error)) == NU\
LL)
{
std::cerr << "Can not create encode" <<std::endl;
return (false);
}
return (true);
}
bool EncoderSystem::decoderCreate()
{
int error;
if ((_decode = opus_decoder_create(SAMPLE_RATE, CHANNELS, &error)) == NULL)
{
std::cerr << "Can not create decoder" <<std::endl;
return (false);
}
return (true);
}
unsigned char* EncoderSystem::encode(unsigned char *data, int size)
{
unsigned char *c_bits = new unsigned char [size];
memcpy(_in, data, size);
/* Encode the frame. */
_nbBytes = opus_encode(_encode, _in, FRAME_SIZE, c_bits, size);
if (_nbBytes<0)
{
std::cerr << "cannot decode" << std::endl;
return NULL;
}
return (c_bits);
}
unsigned char* EncoderSystem::decode(unsigned char *data, int size)
{
int frame_size = opus_decode(_decode, data, size, _out,
MAX_FRAME_SIZE * CHANNELS * 2, 0);
unsigned char *pcm_bytes = new unsigned char [MAX_FRAME_SIZE * CHANNELS * 2];
if (frame_size<0)
{
std::cerr << "cannot decode" << std::endl;
return (NULL);
}
memcpy(pcm_bytes, _out, size);
return (pcm_bytes);
}
int EncoderSystem::getEncodeLen() const { return (this->_nbBytes); }
I really need you, thanks a lot to take your time to help me.
#define PA_SAMPLE_TYPE paInt24
That's probably your problem. As far as I know the standard OPUS codecs take 16-bit integers or 32-bit floating point samples. These correspond to the PortAudio sample types paInt16 and paFloat32.
I recommend getting the types of all your sample buffers correct. Using unsigned char* for formatted sample data is asking for trouble. You need to understand what data types are expected by PortAudio functions and by the OPUS codec functions.

Passing webM file as parameter in C++?

I'm trying to write a program that accepts a webM file (media) as a parameter, and then output the stream details via TTY in as much detail as possible. I figured I'd try to open the file in binary mode, but am not sure where to start.
Thanks for the help.
This sounds like a very high level question, so I'll answer it as such:
If you're creating a command line program in C/C++ that needs to accept parameters, look up how to use the 'argc' and 'argv' parameters to the main() function.
Once you have the parameter being passed into your main function, you will try to open it using some file reading library (there are several to choose from based on your needs and platform). Yes, you will want to open a WebM file in binary mode if the file library cares about the difference. If using fopen(), specify "rb" to read in binary mode-- this won't make any difference on Unix (vs. plain "r") but it will make a big difference on Windows.
From there, you can start reading bytes from the WebM file and processing them. Be advised that WebM is based on the Matroska multimedia format which is quite involved. If you are doing this as an academic exercise, more power to you. If you are looking to get something accomplished on a tight deadline, there are libraries you can call to do the heavy lifting of Matroska parsing on your behalf.
You can do this by making use of libwebm. The sample code is given below. It prints header, cluster, segments etc.
main.cpp
#include "stdio.h"
#include "stdlib.h"
#include "stdbool.h"
#include "string.h"
#include <memory>
#include <mkv/mkvreader.hpp>
#include <mkv/mkvparser.hpp>
#include <mkv/mkvparser.hpp>
#include "webm_parser.h"
static const wchar_t* utf8towcs(const char* str);
bool InputHasCues(const mkvparser::Segment* const segment);
using namespace mkvparser;
/**
* This file reads an webm file. Generates a new file with random number
* of packets in a single webm page.
*/
int webm_parse(int argc, char **argv)
{
int ret = -1;
char *file_out;
char *file_in;
FILE *fd_out = NULL;
MkvReader reader;
if(argc != 3)
{
printf("Usage: ./webm <input webm file> <output webm file>\n");
exit(0);
}
file_in = argv[1];
file_out = argv[2];
printf("\n\nInput webm file = %s , Output webm file = %s\n", file_in, file_out);
fd_out = fopen(file_out, "w+");
if(fd_out == NULL) goto on_error;
if(reader.Open(file_in))
{
printf("Error opening input file %s", file_in);
}
else
{
printf("Successfully opened input file %s\n", file_in);
}
webm_parse_header(&reader);
/** Return 0 on success */
printf("\n");
return ret;
on_error:
if(fd_out) fclose(fd_out);
printf("Error while parse/generate webm file\n");
/** Return -1 on failure */
return -1;
}
int webm_parse_header(void *reader)
{
int maj, min, build, rev;
long long pos = 0;
typedef mkvparser::Segment seg_t;
seg_t* pSegment_;
long long ret;
MkvReader *mkvrdr = (MkvReader *)reader;
EBMLHeader ebmlHeader;
GetVersion(maj, min, build, rev);
printf("libmkv verison: %d.%d.%d.%d\n", maj, min, build, rev);
ebmlHeader.Parse(mkvrdr, pos);
printf("\t\t\t EBML Header\n");
printf("\t\tEBML Version\t\t: %lld\n", ebmlHeader.m_version);
printf("\t\tEBML MaxIDLength\t: %lld\n", ebmlHeader.m_maxIdLength);
printf("\t\tEBML MaxSizeLength\t: %lld\n", ebmlHeader.m_maxSizeLength);
printf("\t\tDoc Type\t\t: %s\n", ebmlHeader.m_docType);
printf("\t\tPos\t\t\t: %lld\n", pos);
ret = seg_t::CreateInstance(mkvrdr, pos, pSegment_);
if (ret)
{
printf("Segment::CreateInstance() failed.\n");
return -1;
}
else
{
printf("Segment::CreateInstance() successful.\n");
}
const std::auto_ptr<seg_t> pSegment(pSegment_);
ret = pSegment->Load();
if (ret < 0)
{
printf("Segment::Load() failed.\n");
return -1;
}
else
{
printf("Segment::Load() successful.\n");
}
const SegmentInfo* const pSegmentInfo = pSegment->GetInfo();
const long long timeCodeScale = pSegmentInfo->GetTimeCodeScale();
const long long duration_ns = pSegmentInfo->GetDuration();
const char* const pTitle_ = pSegmentInfo->GetTitleAsUTF8();
const wchar_t* const pTitle = utf8towcs(pTitle_);
const char* const pMuxingApp_ = pSegmentInfo->GetMuxingAppAsUTF8();
const wchar_t* const pMuxingApp = utf8towcs(pMuxingApp_);
const char* const pWritingApp_ = pSegmentInfo->GetWritingAppAsUTF8();
const wchar_t* const pWritingApp = utf8towcs(pWritingApp_);
printf("\n");
printf("\t\t\t Segment Info\n");
printf("\t\tTimeCodeScale\t\t: %lld \n", timeCodeScale);
printf("\t\tDuration\t\t: %lld\n", duration_ns);
const double duration_sec = double(duration_ns) / 1000000000;
printf("\t\tDuration(secs)\t\t: %7.3lf\n", duration_sec);
if (pTitle == NULL)
printf("\t\tTrack Name\t\t: NULL\n");
else
{
printf("\t\tTrack Name\t\t: %ls\n", pTitle);
delete[] pTitle;
}
if (pMuxingApp == NULL)
printf("\t\tMuxing App\t\t: NULL\n");
else
{
printf("\t\tMuxing App\t\t: %ls\n", pMuxingApp);
delete[] pMuxingApp;
}
if (pWritingApp == NULL)
printf("\t\tWriting App\t\t: NULL\n");
else
{
printf("\t\tWriting App\t\t: %ls\n", pWritingApp);
delete[] pWritingApp;
}
// pos of segment payload
printf("\t\tPosition(Segment)\t: %lld\n", pSegment->m_start);
// size of segment payload
printf("\t\tSize(Segment)\t\t: %lld\n", pSegment->m_size);
const mkvparser::Tracks* pTracks = pSegment->GetTracks();
unsigned long track_num = 0;
const unsigned long num_tracks = pTracks->GetTracksCount();
printf("\n\t\t\t Track Info\n");
while (track_num != num_tracks)
{
const Track* const pTrack = pTracks->GetTrackByIndex(track_num++);
if (pTrack == NULL)
continue;
const long trackType = pTrack->GetType();
const long trackNumber = pTrack->GetNumber();
const unsigned long long trackUid = pTrack->GetUid();
const wchar_t* const pTrackName = utf8towcs(pTrack->GetNameAsUTF8());
printf("\t\tTrack Type\t\t: %ld\n", trackType);
printf("\t\tTrack Number\t\t: %ld\n", trackNumber);
printf("\t\tTrack Uid\t\t: %lld\n", trackUid);
if (pTrackName == NULL)
printf("\t\tTrack Name\t\t: NULL\n");
else
{
printf("\t\tTrack Name\t\t: %ls \n", pTrackName);
delete[] pTrackName;
}
const char* const pCodecId = pTrack->GetCodecId();
if (pCodecId == NULL)
printf("\t\tCodec Id\t\t: NULL\n");
else
printf("\t\tCodec Id\t\t: %s\n", pCodecId);
const char* const pCodecName_ = pTrack->GetCodecNameAsUTF8();
const wchar_t* const pCodecName = utf8towcs(pCodecName_);
if (pCodecName == NULL)
printf("\t\tCodec Name\t\t: NULL\n");
else
{
printf("\t\tCodec Name\t\t: %ls\n", pCodecName);
delete[] pCodecName;
}
if (trackType == mkvparser::Track::kVideo)
{
const VideoTrack* const pVideoTrack =
static_cast<const VideoTrack*>(pTrack);
const long long width = pVideoTrack->GetWidth();
printf("\t\tVideo Width\t\t: %lld\n", width);
const long long height = pVideoTrack->GetHeight();
printf("\t\tVideo Height\t\t: %lld\n", height);
const double rate = pVideoTrack->GetFrameRate();
printf("\t\tVideo Rate\t\t: %f\n", rate);
}
if (trackType == mkvparser::Track::kAudio)
{
const AudioTrack* const pAudioTrack =
static_cast<const AudioTrack*>(pTrack);
const long long channels = pAudioTrack->GetChannels();
printf("\t\tAudio Channels\t\t: %lld\n", channels);
const long long bitDepth = pAudioTrack->GetBitDepth();
printf("\t\tAudio BitDepth\t\t: %lld\n", bitDepth);
const double sampleRate = pAudioTrack->GetSamplingRate();
printf("\t\tAddio Sample Rate\t: %.3f\n", sampleRate);
const long long codecDelay = pAudioTrack->GetCodecDelay();
printf("\t\tAudio Codec Delay\t: %lld\n", codecDelay);
const long long seekPreRoll = pAudioTrack->GetSeekPreRoll();
printf("\t\tAudio Seek Pre Roll\t: %lld\n", seekPreRoll);
}
}
printf("\n\n\t\t\t Cluster Info\n");
const unsigned long clusterCount = pSegment->GetCount();
printf("\t\tCluster Count\t: %ld\n\n", clusterCount);
if (clusterCount == 0)
{
printf("\t\tSegment has no clusters.\n");
return -1;
}
const mkvparser::Cluster* pCluster = pSegment->GetFirst();
while ((pCluster != NULL) && !pCluster->EOS())
{
const long long timeCode = pCluster->GetTimeCode();
printf("\t\tCluster Time Code\t: %lld\n", timeCode);
const long long time_ns = pCluster->GetTime();
printf("\t\tCluster Time (ns)\t: %lld\n", time_ns);
const BlockEntry* pBlockEntry;
long status = pCluster->GetFirst(pBlockEntry);
if (status < 0) // error
{
printf("\t\tError parsing first block of cluster\n");
fflush(stdout);
return -1;
}
while ((pBlockEntry != NULL) && !pBlockEntry->EOS())
{
const Block* const pBlock = pBlockEntry->GetBlock();
const long long trackNum = pBlock->GetTrackNumber();
const unsigned long tn = static_cast<unsigned long>(trackNum);
const Track* const pTrack = pTracks->GetTrackByNumber(tn);
if (pTrack == NULL)
printf("\t\t\tBlock\t\t:UNKNOWN TRACK TYPE\n");
else
{
const long long trackType = pTrack->GetType();
const int frameCount = pBlock->GetFrameCount();
const long long time_ns = pBlock->GetTime(pCluster);
const long long discard_padding = pBlock->GetDiscardPadding();
printf("\t\t\tBlock\t\t:%s,%s,%15lld,%lld\n",
(trackType == mkvparser::Track::kVideo) ? "V" : "A",
pBlock->IsKey() ? "I" : "P", time_ns, discard_padding);
for (int i = 0; i < frameCount; ++i)
{
const Block::Frame& theFrame = pBlock->GetFrame(i);
const long size = theFrame.len;
const long long offset = theFrame.pos;
printf("\t\t\t %15ld,%15llx\n", size, offset);
}
}
status = pCluster->GetNext(pBlockEntry, pBlockEntry);
if (status < 0)
{
printf("\t\t\tError parsing next block of cluster\n");
fflush(stdout);
return -1;
}
}
pCluster = pSegment->GetNext(pCluster);
}
if (InputHasCues(pSegment.get()))
{
// Walk them.
const mkvparser::Cues* const cues = pSegment->GetCues();
const mkvparser::CuePoint* cue = cues->GetFirst();
int cue_point_num = 1;
printf("\t\tCues\n");
do
{
for (track_num = 0; track_num < num_tracks; ++track_num)
{
const mkvparser::Track* const track =
pTracks->GetTrackByIndex(track_num);
const mkvparser::CuePoint::TrackPosition* const track_pos =
cue->Find(track);
if (track_pos != NULL)
{
const char track_type =
(track->GetType() == mkvparser::Track::kVideo) ? 'V' : 'A';
printf(
"\t\t\tCue Point %4d Track %3lu(%c) Time %14lld "
"Block %4lld Pos %8llx\n",
cue_point_num, track->GetNumber(), track_type,
cue->GetTime(pSegment.get()), track_pos->m_block,
track_pos->m_pos);
}
}
cue = cues->GetNext(cue);
++cue_point_num;
} while (cue != NULL);
}
const mkvparser::Tags* const tags = pSegment->GetTags();
if (tags && tags->GetTagCount() > 0)
{
printf("\t\tTags\n");
for (int i = 0; i < tags->GetTagCount(); ++i)
{
const mkvparser::Tags::Tag* const tag = tags->GetTag(i);
printf("\t\t\tTag\n");
for (int j = 0; j < tag->GetSimpleTagCount(); j++)
{
const mkvparser::Tags::SimpleTag* const simple_tag =
tag->GetSimpleTag(j);
printf("\t\t\t\tSimple Tag \"%s\" Value \"%s\"\n",
simple_tag->GetTagName(), simple_tag->GetTagString());
}
}
}
fflush(stdout);
return 0;
on_error:
return -1;
}
static const wchar_t* utf8towcs(const char* str)
{
if (str == NULL)
return NULL;
// TODO: this probably requires that the locale be
// configured somehow:
const size_t size = mbstowcs(NULL, str, 0);
if (size == 0)
return NULL;
wchar_t* const val = new wchar_t[size + 1];
mbstowcs(val, str, size);
val[size] = L'\0';
return val;
}
bool InputHasCues(const mkvparser::Segment* const segment)
{
const mkvparser::Cues* const cues = segment->GetCues();
if (cues == NULL)
return false;
while (!cues->DoneParsing())
cues->LoadCuePoint();
const mkvparser::CuePoint* const cue_point = cues->GetFirst();
if (cue_point == NULL)
return false;
return true;
}

FILE * and istream: connect the two?

Suppose I "popen" an executable, I get a FILE* in return. Furthermore, suppose I'd like to "connect" this file to an istream object for easier processing, is there a way to do this?
You can get away by deriving std::basic_streambuf or std::streambuf classes.
Something along these lines:
#include <stdio.h>
#include <iostream>
#define BUFFER_SIZE 1024
class popen_streambuf : public std::streambuf {
public:
popen_streambuf() : fp(NULL) {
}
~popen_streambuf() {
close();
}
popen_streambuf *open(const char *command, const char *mode) {
fp = popen(command, mode);
if (fp == NULL)
return NULL;
buffer = new char_type[BUFFER_SIZE];
// It's good to check because exceptions can be disabled
if (buffer == NULL) {
close();
return NULL;
}
setg(buffer, buffer, buffer);
return this;
}
void close() {
if (fp != NULL) {
pclose(fp);
fp = NULL;
}
}
std::streamsize xsgetn(char_type *ptr, std::streamsize n) {
std::streamsize got = showmanyc();
if (n <= got) {
memcpy(ptr, gptr(), n * sizeof(char_type));
gbump(n);
return n;
}
memcpy(ptr, gptr(), got * sizeof(char_type));
gbump(got);
if (traits_type::eof() == underflow()) {
return got;
}
return (got + xsgetn(ptr + got, n - got));
}
int_type underflow() {
if (gptr() == 0) {
return traits_type::eof();
}
if (gptr() < egptr()) {
return traits_type::to_int_type(*gptr());
}
size_t len = fread(eback(), sizeof(char_type), BUFFER_SIZE, fp);
setg(eback(), eback(), eback() + (sizeof(char_type) * len));
if (0 == len) {
return traits_type::eof();
}
return traits_type::to_int_type(*gptr());
}
std::streamsize showmanyc() {
if (gptr() == 0) {
return 0;
}
if (gptr() < egptr()) {
return egptr() - gptr();
}
return 0;
}
private:
FILE *fp;
char_type *buffer;
};
int main(int argc, char *argv)
{
char c;
popen_streambuf sb;
std::istream is(&sb);
if (NULL == sb.open("ls -la", "r")) {
return 1;
}
while (is.read(&c, 1)) {
std::cout << c;
}
return 0;
}
There is no standard way but if you want a quick solution you can get the file descriptor with fileno() and then use Josuttis' fdstream. There may be similar efforts around but I used this in the distant past and it worked fine. If nothing else it should be a very good map to implementing your own.
Sure there's a way, implement your own istream that can be constructed from a FILE*.
If you're asking whether there is a standard way to do this, then no.