How to convert 24bit bitmap buffer to base64? - c
char * lpbitmap = NULL;
BITMAPFILEHEADER bmfHeader;
BITMAPINFOHEADER bi;
bi.biSize = sizeof(BITMAPINFOHEADER);
bi.biWidth = bmpScreen.bmWidth;
bi.biHeight = bmpScreen.bmHeight;
bi.biPlanes = 1;
bi.biBitCount = 24;
bi.biCompression = BI_RGB;
bi.biSizeImage = 0;
bi.biXPelsPerMeter = 0;
bi.biYPelsPerMeter = 0;
bi.biClrUsed = 0;
bi.biClrImportant = 0;
dwBmpSize = ((bmpScreen.bmWidth * bi.biBitCount + 31) / 32) * 4 * bmpScreen.bmHeight;
hDIB = GlobalAlloc(GHND, dwBmpSize);
lpbitmap = (char*)GlobalLock(hDIB);
I am using the windows GDI header file to create a bitmap, the goal is to convert the lpbitmap buffer to a base64 string so that it can be represented as such data:image/bmp;base64,Qk06
as far as I understand the bitmap is 24bit where every 3 chars represent RGB values example
How to convert each RGB value into a base64 value
Update
I changed the bitcount to 24
Below is my conversion of LihO's C++ answer to C: Base64 decode snippet in C++
As I mentioned in the comments, I thought it would be simple. But,there wasn't a simple cookbook to give to someone not familiar with C++. So, to do the conversion properly, I did it myself.
And, there were a few issues:
The answer did a lot of unnecessary buffer copying.
Using std::string and std::vector, although pretty fast, are somewhat slower than using raw byte buffers.
Using base64_chars.find is O(n) but if an inverse table is created/used, it can be O(1).
The answer did not support line breaks (e.g. \n) as most base64 programs do.
Anyway, below are the source files I came up with. They can be compiled with:
cc -I. -o b64test b64test.c base64.c dbgcom.c
Note that the mmap mode (i.e. -m) is untested.
FILE: base64.h
// base64.h -- base64 definitions
#ifndef _base64_h_
#define _base64_h_
#include <dbgcom.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
typedef struct {
u32 buf_opt; // buffer options
const char *buf_tag; // buffer name
byte *buf_base; // buffer pointer
size_t buf_len; // buffer length
int buf_fdmap; // mmap file descriptor
} b64buf_t;
#define B64BUFDEF(_sym) \
b64buf_t _sym = { .buf_tag = #_sym }
typedef struct {
//u32 ctl_opt; // options
const char *ctl_tag; // control name
b64buf_t ctl_inb; // input buffer
b64buf_t ctl_out; // output buffer
int ctl_wrapnow; // last output char was newline
int ctl_wraplen; // output wrap length
int ctl_wrapmax; // output wrap max
int ctl_fdchk; // file cross check
} b64ctl_t;
#define B64CTLDEF(_sym) \
b64ctl_t _sym = { .ctl_tag = #_sym }
#define B64MMAP (1u << 0) // 1=use mmap on output
#define B64TRIM (1u << 1) // 1=trim output file
// b64encode -- encode raw data to base64
// RETURNS actual output length
size_t
b64encode(b64ctl_t *ctl);
// b64decode -- decode base64 into raw binary
// RETURNS: actual output length
size_t
b64decode(b64ctl_t *ctl);
// b64bufdup -- safe buffer duplicate
void
b64bufdup(b64buf_t *dst,const b64buf_t *src);
// b64bufput -- output buffer to file
void
b64bufput(const b64buf_t *bufp,const char *ofile);
// b64bufget -- input file to buffer
void
b64bufget(b64buf_t *bufp,const char *ifile);
// b64setup -- passive setup
void
b64setup(b64ctl_t *ctl,u32 opt,const char *tag);
// b64init_encode -- initialize for encode
// RETURNS: 0=okay, -1=error
int
b64init_encode(b64ctl_t *ctl,const b64buf_t *inb,int wrapmax);
// b64init_decode -- initialize for decode
// RETURNS: 0=okay, -1=error
int
b64init_decode(b64ctl_t *ctl,b64buf_t *inb);
// b64destroy -- destroy/deinit output buffer
void
b64destroy(b64ctl_t *ctl);
// b64bufrls -- destroy/deinit output buffer
void
b64bufrls(b64buf_t *buf,const char *who);
#endif
FILE: base64.c
// base64.c -- base 64 encoder/decoder
#include <base64.h>
#include <ctype.h>
#include <sys/stat.h>
#include <sys/mman.h>
static const char *base64_chars =
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz"
"0123456789+/";
#ifndef B64DECODE_FAST
#define B64DECODE_FAST 1
#endif
#if B64DECODE_FAST
static byte decode_fast[256];
#endif
#define FMT "%2.2X/%c"
#define PRT(_c) _c,PRTABLE(_c)
#define PUT4(_idx,_val) \
arr4[_idx] = _val
#define PUTE(_idx,_val) \
arr4[_idx] = base64_chars[_val]
#define OUTLEN(_buf,_ptr) \
(_ptr - (byte *) (_buf)->buf_base)
// encode_xcheck -- cross-check encoding
#if B64ENCODE_XCHECK
#define encode_xcheck(_ctl,_arr4,_a4siz,_arr3,_a3siz,_pad) \
_encode_xcheck(_ctl,_arr4,_a4siz,_arr3,_a3siz,_pad)
static void
_encode_xcheck(b64ctl_t *ctl,
const byte *arr4,int a4siz,
const byte *arr3,int a3siz,int pad)
{
int xlen;
int oidx;
byte buf[a4siz];
dbgprt(ZPXHOWCHR,"encode_xcheck: ENTER a4siz=%d a3siz=%d pad=%d\n",
a4siz,a3siz,pad);
xlen = read(ctl->ctl_fdchk,buf,a4siz);
if (xlen != a4siz)
sysfault("encode_xcheck: read error -- a4siz=%d xlen=%d\n",
a4siz,xlen);
// check for error/mismatch
int errany = 0;
for (oidx = 0; oidx < a4siz; ++oidx) {
errany = (arr4[oidx] != buf[oidx]);
if (errany)
break;
}
do {
// only print if verbose mode or we have an error
if (! XVERBOSE) {
if (! errany)
break;
}
int totsiz = a4siz;
if (a3siz > totsiz)
totsiz = a3siz;
for (oidx = 0; oidx < totsiz; ++oidx) {
byte bp = 0;
byte a4 = 0;
byte a3 = 0;
size_t o4off = 0;
size_t o3off = 0;
if (oidx < a4siz) {
bp = buf[oidx];
a4 = arr4[oidx];
o4off = OUTLEN(&ctl->ctl_out,arr4);
}
if (oidx < a3siz) {
a3 = arr3[oidx];
o3off = OUTLEN(&ctl->ctl_inb,arr3);
}
int errcur = (arr4[oidx] != buf[oidx]);
printf("encode_xcheck: arr=%8.8zX/",o4off);
if (pad)
printf("censored");
else
printf("%8.8zX",o3off);
printf(" oidx=%d exp=" FMT " act=" FMT " arr3=" FMT,
oidx,PRT(bp),PRT(a4),PRT(a3));
if (errany)
printf(" ANY");
if (errcur)
printf("/CUR");
printf("\n");
}
if (errany)
sysfault("encode_xcheck: fault\n");
} while (0);
dbgprt(ZPXHOWCHR,"encode_xcheck: EXIT\n");
}
#else
#define encode_xcheck(_ctl,_arr4,_a4siz,_arr3,_a3siz,_pad) \
do { } while (0)
#endif
// encode_wrap -- perform encoding and inject newline
static inline_nodebug byte *
encode_wrap(b64ctl_t *ctl,byte *arr4)
{
dbgprt(ZPXHOWCHR,"encode_wrap: ENTER ctl_wraplen=%d ctl_wrapmax=%d\n",
ctl->ctl_wraplen,ctl->ctl_wrapmax);
do {
// bug out if wrap disabled
if (ctl->ctl_wrapmax <= 0)
break;
// wait for wrap
ctl->ctl_wraplen += 4;
ctl->ctl_wrapnow = 0;
if (ctl->ctl_wraplen < ctl->ctl_wrapmax)
break;
ctl->ctl_wraplen = 0;
ctl->ctl_wrapnow = 1;
PUT4(0,'\n');
encode_xcheck(ctl,arr4,1,NULL,0,-1);
++arr4;
} while (0);
dbgprt(ZPXHOWCHR,"encode_wrap: EXIT ctl_wraplen=%d ctl_wrapnow=%d\n",
ctl->ctl_wraplen,ctl->ctl_wrapnow);
return arr4;
}
// encode_putx -- perform encoding
static inline_nodebug byte *
encode_putx(b64ctl_t *ctl,byte *arr4,const byte *arr3,int padlen)
{
dbgprt(ZPXHOWCHR,"b64encode: LOOP arr3=(" FMT " " FMT " " FMT ") padlen=%d\n",
PRT(arr3[0]),PRT(arr3[1]),PRT(arr3[2]),padlen);
PUTE(0,(arr3[0] & 0xfc) >> 2);
PUTE(1,((arr3[0] & 0x03) << 4) + ((arr3[1] & 0xf0) >> 4));
PUTE(2,((arr3[1] & 0x0f) << 2) + ((arr3[2] & 0xc0) >> 6));
PUTE(3,arr3[2] & 0x3f);
switch (padlen) {
case 2:
PUT4(2,'=');
// fall through
case 1:
PUT4(3,'=');
break;
}
encode_xcheck(ctl,arr4,4,arr3,3,padlen);
arr4 += 4;
return arr4;
}
// is_base64 -- ensure char is a valid base64 encoding char
#if ! B64DECODE_FAST
static inline int
is_base64(byte c)
{
return (isalnum(c) || (c == '+') || (c == '/'));
}
#endif
// decode_find -- convert encoded base64 char into binary byte
static inline byte
decode_find(byte chr)
{
byte out;
#if B64DECODE_FAST
out = decode_fast[chr];
#else
const char *find = strchr(base64_chars,chr);
out = find - base64_chars;
#endif
dbgprt(ZPXHOWCHR,"decode_find: XLAT out=" FMT " chr=" FMT "\n",
PRT(out),PRT(chr));
if (out == 0xFF)
sysfault("b64decode: NONBASE64 chr=" FMT "\n",PRT(chr));
return out;
}
// decode_put -- convert 4 byte encoded base64 cell into 3 binary bytes
static inline_nodebug byte *
decode_put(byte *arr3,byte *arr4,int a4len)
{
int idx;
int a3len;
dbgprt(ZPXHOWCHR,"decode_put: ENTER a4len=%d\n",a4len);
// convert to binary codes
idx = 0;
for (; idx < a4len; ++idx)
arr4[idx] = decode_find(arr4[idx]);
// add zero padding
#if 0
for (; idx < 4; ++idx)
arr4[idx] = 0;
#endif
a3len = (a4len * 3) / 4;
// store 3 binary chars for 4 byte cell
arr3[0] = (arr4[0] << 2) + ((arr4[1] & 0x30) >> 4);
arr3[1] = ((arr4[1] & 0xf) << 4) + ((arr4[2] & 0x3c) >> 2);
arr3[2] = ((arr4[2] & 0x3) << 6) + arr4[3];
#if B64VERBOSE
for (idx = 0; idx < a3len; ++idx)
dbgprt(ZPXHOWCHR,"decode_put: arr3[%d]=" FMT "\n",PRT(arr3[idx]));
#endif
// advance output pointer
arr3 += a3len;
dbgprt(ZPXHOWCHR,"decode_put: EXIT a3len=%d\n",a3len);
return arr3;
}
// finish -- finish an operation
static size_t
finish(b64ctl_t *ctl,byte *out)
{
b64buf_t *buf = &ctl->ctl_out;
size_t outlen = OUTLEN(buf,out);
if (outlen > buf->buf_len)
sysfault("finish: buffer overflow -- buf_len=%zu outlen=%zu\n",
buf->buf_len,outlen);
buf->buf_len = outlen;
return outlen;
}
// b64encode -- encode raw data to base64
// RETURNS actual output length
size_t
b64encode(b64ctl_t *ctl)
{
const byte *inb = ctl->ctl_inb.buf_base;
ssize_t inblen = ctl->ctl_inb.buf_len;
byte *arr4 = ctl->ctl_out.buf_base;
int anyflg = (inblen > 0);
dbgprt(ZPXHOWB64,"b64encode: ENTER inb=%p inblen=%zu\n",inb,inblen);
for (; inblen >= 3; inblen -= 3, inb += 3) {
arr4 = encode_putx(ctl,arr4,inb,0);
arr4 = encode_wrap(ctl,arr4);
}
if (inblen) {
byte arr3[3];
u32 j = 0;
int padlen = 3 - inblen;
dbgprt(ZPXHOWB64,"b64encode: POST inblen=%zu padlen=%d\n",
inblen,padlen);
// copy over valid bytes
for (; inblen > 0; --inblen, ++j)
arr3[j] = inb[j];
// add zeroes as padding?
for (; j < 3; ++j)
arr3[j] = 0;
// add final padding
arr4 = encode_putx(ctl,arr4,arr3,padlen);
arr4 = encode_wrap(ctl,arr4);
}
// sequence should end with newline
do {
dbgprt(ZPXHOWB64,"b64encode: WRAP anyflg=%d ctl_wrapnow=%d\n",
anyflg,ctl->ctl_wrapnow);
// no newline generation
if (ctl->ctl_wrapmax <= 0)
break;
// no legit data
if (! anyflg)
break;
// don't double up newlines if we just did a newline
if (ctl->ctl_wrapnow)
break;
PUT4(0,'\n');
encode_xcheck(ctl,arr4,1,NULL,0,0);
++arr4;
} while (0);
// always add EOS
#if 0
*arr4 = 0;
#endif
size_t outlen = finish(ctl,arr4);
dbgprt(ZPXHOWB64,"b64encode: EXIT outlen=%zu\n",outlen);
return outlen;
}
// b64decode -- decode base64 into raw binary
// RETURNS: actual output length
size_t
b64decode(b64ctl_t *ctl)
{
const char *inb = (const char *) ctl->ctl_inb.buf_base;
size_t inblen = ctl->ctl_inb.buf_len;
size_t inbidx = 0;
byte *arr3 = ctl->ctl_out.buf_base;
int outidx = 0;
byte arr4[4];
dbgprt(ZPXHOWB64,"b64decode: ENTER inb=%p\n",inb);
for (inbidx = 0; inbidx < inblen; ++inbidx) {
int chr = inb[inbidx];
dbgprt(ZPXHOWCHR,"b64decode: LOOP chr=" FMT "\n",PRT(chr));
// stop when we hit a pad char
if (chr == '=')
break;
// ignore newlines
if (chr == '\n')
continue;
// not a valid char
#if ! B64DECODE_FAST
if (! is_base64(chr)) {
sysfault("b64decode: NONBASE64 chr=" FMT "\n",PRT(chr));
break;
}
#endif
arr4[outidx++] = chr;
if (outidx == 4) {
arr3 = decode_put(arr3,arr4,4);
outidx = 0;
}
}
if (outidx > 0) {
dbgprt(ZPXHOWB64,"b64decode: POST outidx=%d inblen=%zu\n",
outidx,inblen);
// fill remainder with pad/zeroes
for (inbidx = outidx; inbidx < 4; ++inbidx)
arr4[inbidx] = 0;
arr3 = decode_put(arr3,arr4,outidx);
}
size_t outlen = finish(ctl,arr3);
dbgprt(ZPXHOWB64,"b64decode: EXIT outlen=%zu\n",outlen);
return outlen;
}
// b64bufdup -- safe buffer duplicate
void
b64bufdup(b64buf_t *dst,const b64buf_t *src)
{
const char *tag = dst->buf_tag;
dbgprt(ZPXHOWB64,"b64bufdup: ENTER dst=%s/%p src=%s/%p\n",
dst->buf_tag,dst->buf_base,src->buf_tag,src->buf_base);
if (dst->buf_base != NULL)
sysfault("b64bufdup: non-null -- dst=%s buf_base=%p src=%s\n",
tag,dst->buf_base,src->buf_tag);
*dst = *src;
dst->buf_tag = tag;
dbgprt(ZPXHOWB64,"b64bufdup: EXIT\n");
}
// b64bufput -- output buffer to file
void
b64bufput(const b64buf_t *bufp,const char *ofile)
{
int fd;
b64buf_t buf_;
b64buf_t *buf = &buf_;
ssize_t xlen;
*buf = *bufp;
printf("b64bufput: %s buf_base=%p buf_len=%zu\n",
ofile,buf->buf_base,buf->buf_len);
do {
if (buf->buf_opt & B64MMAP)
break;
fd = open(ofile,O_WRONLY | O_TRUNC | O_CREAT,0644);
if (fd < 0)
sysfault("b64bufput: unable to open '%s' -- %s\n",
ofile,strerror(errno));
for (; buf->buf_len > 0;
buf->buf_len -= xlen, buf->buf_base += xlen) {
xlen = write(fd,buf->buf_base,buf->buf_len);
if (xlen < 0)
sysfault("bufput: write error -- %s\n",strerror(errno));
}
CLOSEME(fd);
} while (0);
}
// b64bufget -- input file to buffer
void
b64bufget(b64buf_t *buf,const char *ifile)
{
struct stat st;
size_t cap;
int fd;
const char *etag = NULL;
ssize_t xlen;
do {
fd = open(ifile,O_RDONLY);
if (fd < 0) {
etag = "open";
break;
}
if (buf->buf_opt & B64MMAP) {
buf->buf_fdmap = fd;
// get file size
if (fstat(fd,&st) < 0) {
etag = "fstat";
break;
}
buf->buf_len = st.st_size;
buf->buf_base = mmap(NULL,buf->buf_len,PROT_READ,
MAP_SHARED,buf->buf_fdmap,0);
if (buf->buf_base == MAP_FAILED) {
etag = "mmap";
break;
}
break;
}
cap = 0;
buf->buf_len = 0;
buf->buf_base = NULL;
while (1) {
if (buf->buf_len >= cap) {
cap += 4096;
buf->buf_base = realloc(buf->buf_base,cap + 1);
if (buf->buf_base == NULL) {
etag = "realloc";
break;
}
}
xlen = read(fd,&buf->buf_base[buf->buf_len],cap - buf->buf_len);
if (xlen < 0) {
etag = "read";
break;
}
if (xlen == 0)
break;
buf->buf_len += xlen;
}
} while (0);
if (etag != NULL)
sysfault("b64bufget: unable to %s '%s' -- %s\n",
etag,ifile,strerror(errno));
do {
if (buf->buf_opt & B64MMAP)
break;
CLOSEME(buf->buf_fdmap);
cap = buf->buf_len;
buf->buf_base[cap] = 0;
buf->buf_base = realloc(buf->buf_base,cap + 1);
if (buf->buf_base == NULL)
sysfault("b64bufget: realloc fail -- %s\n",strerror(errno));
} while (0);
printf("b64bufget: %s buf_base=%p buf_len=%zu\n",
ifile,buf->buf_base,buf->buf_len);
}
// b64setup -- passive setup
void
b64setup(b64ctl_t *ctl,u32 opt,const char *tag)
{
b64buf_t *buf;
memset(ctl,0,sizeof(*ctl));
ctl->ctl_tag = tag;
buf = &ctl->ctl_out;
buf->buf_fdmap = -1;
buf->buf_opt = opt;
buf->buf_tag = "ctl_out";
buf = &ctl->ctl_inb;
buf->buf_fdmap = -1;
buf->buf_opt = opt;
buf->buf_tag = "ctl_inb";
ctl->ctl_fdchk = -1;
}
// init_outbuf -- initialize output buffer
static int
init_outbuf(b64ctl_t *ctl,size_t outlen)
{
b64buf_t *buf = &ctl->ctl_out;
int err = -1;
dbgprt(ZPXHOWB64,"init_outbuf: ENTER ctl=%s buf=%s buf_base=%p buf_len=%zu outlen=%zu\n",
ctl->ctl_tag,buf->buf_tag,buf->buf_base,buf->buf_len,outlen);
buf->buf_len = outlen;
do {
if (! (buf->buf_opt & B64MMAP)) {
buf->buf_base = realloc(buf->buf_base,outlen);
if (buf->buf_base == NULL)
break;
err = 0;
break;
}
if (ftruncate(buf->buf_fdmap,outlen) < 0)
break;
buf->buf_base = mmap(NULL,outlen,PROT_READ | PROT_WRITE,
MAP_SHARED,buf->buf_fdmap,0);
if (buf->buf_base == MAP_FAILED) {
buf->buf_base = NULL;
break;
}
err = 0;
} while (0);
dbgprt(ZPXHOWB64,"init_outbuf: EXIT err=%d\n",err);
return err;
}
// b64init_encode -- initialize for encode
// RETURNS: 0=okay, -1=error
int
b64init_encode(b64ctl_t *ctl,const b64buf_t *inb,int wrapmax)
{
size_t outlen;
// copy in the buffer
b64bufdup(&ctl->ctl_inb,inb);
// we need for 4 bytes of output for each 3 bytes of input
outlen = inb->buf_len;
outlen *= 4;
outlen /= 3;
outlen += 4;
// space for padding
outlen += 4;
// we wrap with newline every N bytes
if (wrapmax == 0)
wrapmax = 76;
ctl->ctl_wrapmax = wrapmax;
if (wrapmax > 0)
outlen += (outlen + wrapmax) / wrapmax;
return init_outbuf(ctl,outlen);
}
#if B64DECODE_FAST
// init_fast -- initialize fast decode lookup
static void
init_fast(void)
{
const char *cp = base64_chars;
memset(decode_fast,0xFF,sizeof(decode_fast));
for (int chr = *cp; chr != 0; ++cp, chr = *cp) {
size_t off = cp - base64_chars;
decode_fast[chr] = off;
dbgprt(ZPXHOWB64,"init_fast: FASTINIT chr='%c' off=%zu\n",
chr,off);
}
}
#endif
// b64init_decode -- initialize for decode
// RETURNS: 0=okay, -1=error
int
b64init_decode(b64ctl_t *ctl,b64buf_t *inb)
{
size_t outlen;
int err;
dbgprt(ZPXHOWB64,"b64init_decode: ENTER buf_len=%zu\n",inb->buf_len);
#if B64DECODE_FAST
if (decode_fast['B'] == 0)
init_fast();
#endif
if (inb != &ctl->ctl_inb)
ctl->ctl_inb = *inb;
inb = &ctl->ctl_inb;
// caller may already know the input length, but ...
#if 0
if (inb->buf_len == 0) {
inb->buf_len = strlen(inb->buf_base);
dbgprt(ZPXHOWB64,"b64init_decode: STRLEN buf_len=%zu\n",inb->buf_len);
}
#endif
// we need for 3 bytes of output for each 4 bytes of input
outlen = inb->buf_len;
outlen *= 3;
outlen += 3;
outlen /= 4;
err = init_outbuf(ctl,outlen);
dbgprt(ZPXHOWB64,"b64init_decode: EXIT err=%d outlen=%zu\n",err,outlen);
return err;
}
// b64destroy -- destroy/deinit output buffer
void
b64destroy(b64ctl_t *ctl)
{
b64bufrls(&ctl->ctl_out,"ctl_out");
b64bufrls(&ctl->ctl_inb,"ctl_inb");
}
// b64bufrls -- destroy/deinit output buffer
void
b64bufrls(b64buf_t *buf,const char *who)
{
size_t outlen = buf->buf_len;
int err = -1;
dbgprt(ZPXHOWB64,"b64bufrls: ENTER buf_opt=%8.8X buf_base=%p outlen=%zu (from %s)\n",
buf->buf_opt,buf->buf_base,outlen,who);
do {
if (! (buf->buf_opt & B64MMAP)) {
FREEME(buf->buf_base);
err = 0;
break;
}
if (munmap(buf->buf_base,outlen) < 0)
break;
if (buf->buf_opt & B64TRIM) {
if (ftruncate(buf->buf_fdmap,outlen) < 0)
break;
}
CLOSEME(buf->buf_fdmap);
} while (0);
if (err < 0)
exit(1);
buf->buf_base = NULL;
buf->buf_len = 0;
dbgprt(ZPXHOWB64,"b64bufrls: EXIT\n");
}
FILE: b64test.c
// b64test.c -- test program for base64
#include <base64.h>
int opt_a; // exhaustive test
int opt_L; // binary file length
int opt_k; // keep temp files
int opt_m; // use mmap
u32 opt_R = 1; // random seed
int opt_T; // number of tests
int opt_W; // wrap length
int tstno = 1; // current test number
#define ALLFILES(_cmd) \
_cmd(bin) \
_cmd(encexp) \
_cmd(encact) \
_cmd(dcdexp) \
_cmd(dcdact)
#define FILEDEF(_pre) \
const char *_pre##_file = #_pre ".TMP";
ALLFILES(FILEDEF)
#define FILERM(_pre) \
unlink(_pre##_file);
// initial random binary buffer
B64BUFDEF(binbuf);
// encoding control
B64BUFDEF(encbuf);
B64CTLDEF(ctlenc);
// decoding control
B64BUFDEF(dcdbuf);
B64CTLDEF(ctldcd);
int
doexec(const char *cmd)
{
printf("DOEXEC: %s\n",cmd);
int ignflg = (cmd[0] == '!');
if (ignflg)
++cmd;
int code = system(cmd);
if (code && (! ignflg))
exit(1);
return code;
}
int
xrand(void)
{
return rand_r(&opt_R);
}
// doclean -- remove temp files
void
doclean(void)
{
do {
if (opt_k)
break;
ALLFILES(FILERM);
} while (0);
}
void
dotest(int binlen)
{
int err;
u32 opt = 0;
b64ctl_t *ctl;
b64buf_t *buf;
char cmd[1000];
printf("\n");
for (int col = 1; col <= 80; ++col)
putchar('-');
printf("\n");
dbgprt(ZPXHOWB64,"dotest: ENTER binlen=%d\n",binlen);
buf = &binbuf;
if (binlen <= 0)
buf->buf_len = -binlen;
else
buf->buf_len = xrand() % binlen;
printf("dotest: %d -- R=%u L=%8.8zX/%zu\n",
tstno,opt_R,buf->buf_len,buf->buf_len);
doclean();
if (opt_m) {
opt |= B64MMAP;
opt |= B64TRIM;
}
// NOTE: this gets freed in the b64destroy for ctlenc below
buf->buf_base = NULL;
buf->buf_base = realloc(buf->buf_base,buf->buf_len);
if (buf->buf_base == NULL)
sysfault("dotest: realloc failure -- %s\n",strerror(errno));
// get a random buffer
for (size_t bufidx = 0; bufidx < buf->buf_len; ++bufidx)
buf->buf_base[bufidx] = xrand();
// dump it for base64 program
b64bufput(buf,bin_file);
// have base64 encode it
sprintf(cmd,"base64 %s > %s",bin_file,encexp_file);
doexec(cmd);
ctl = &ctlenc;
b64setup(ctl,opt,"ctlenc");
err = b64init_encode(ctl,buf,opt_W);
if (err < 0)
sysfault("dotest: b64init_encode failure -- %s\n",strerror(errno));
#if B64ENCODE_XCHECK
ctl->ctl_fdchk = open(encexp_file,O_RDONLY);
#endif
// have our routine encode it
b64encode(ctl);
#if B64ENCODE_XCHECK
CLOSEME(ctl->ctl_fdchk);
#endif
// save it to a file
b64bufput(&ctl->ctl_out,encact_file);
b64destroy(ctl);
// compare them
sprintf(cmd,"diff -u %s %s",encexp_file,encact_file);
doexec(cmd);
// decode it
sprintf(cmd,"base64 -d %s > %s",encexp_file,dcdexp_file);
doexec(cmd);
// passive setup
ctl = &ctldcd;
b64setup(ctl,opt,"ctldcd");
// load up the encoded file into the decode input buffer
b64bufget(&dcdbuf,encact_file);
// decode the data
err = b64init_decode(ctl,&dcdbuf);
if (err < 0)
sysfault("dotest: b64init_decode failure -- %s\n",strerror(errno));
// have our routine decode it
b64decode(ctl);
b64bufput(&ctl->ctl_out,dcdact_file);
b64destroy(ctl);
// compare them
sprintf(cmd,"cmp %s %s",dcdexp_file,dcdact_file);
doexec(cmd);
// final temp file cleanup
doclean();
printf("dotest: complete\n");
dbgprt(ZPXHOWB64,"dotest: EXIT\n");
}
int
main(int argc,char **argv)
{
char *cp;
--argc;
++argv;
setlinebuf(stdout);
// use a special output directory
do {
cp = getenv("GENDIR");
if (cp == NULL)
break;
printf("GENDIR = %s\n",cp);
if (chdir(cp) < 0)
sysfault("main: chdir fault -- %s\n",strerror(errno));
} while (0);
// parse options
for (; argc > 0; --argc, ++argv) {
cp = *argv;
if (*cp != '-')
break;
cp += 2;
switch (cp[-1]) {
case 'a':
opt_a = (*cp != 0) ? atoi(cp) : 1;
break;
case 'L':
opt_L = (*cp != 0) ? atoi(cp) : 1000;
break;
case 'k':
opt_k = ! opt_k;
break;
case 'm':
opt_m = ! opt_m;
break;
case 'R':
opt_R = (*cp != 0) ? atoi(cp) : 1;
break;
case 'T':
opt_T = (*cp != 0) ? atoi(cp) : 100;
break;
case 'W':
opt_W = atoi(cp);
break;
}
}
// ensure at least one test
if (opt_T <= 0)
opt_T = 1;
do {
// ensure we have a non-zero length
if (opt_L == 0)
opt_L = 100;
// do random testing
if (opt_a < 0) {
for (; tstno <= opt_T; ++tstno)
dotest(opt_L);
break;
}
// get absolute value
if (opt_L < 0)
opt_L = -opt_L;
// ensure we get at least one test
if (opt_L < opt_a)
opt_L = opt_a;
// do a range of explicit lengths
for (int binlen = opt_a; binlen <= opt_L; ++binlen, ++tstno)
dotest(-binlen);
} while (0);
printf("%d tests completed\n",tstno);
return 0;
}
FILE: dbgcom.h
// dbgflg.h -- base/debug definitions
#ifndef _dbgflg_h_
#define _dbgflg_h_
#include <stdio.h>
#include <stdlib.h>
typedef unsigned char byte;
typedef unsigned int u32;
#define ZPXHOWALL(_cmd) \
_cmd(ZPXHOWB64) \
_cmd(ZPXHOWCHR) \
_cmd(ZPXHOWTST)
#define _DBGENUM(_sym) \
_sym,
enum {
ZPXHOWANY,
ZPXHOWALL(_DBGENUM)
ZPXHOWMAX
};
byte dbgflg[ZPXHOWMAX];
static inline byte
dbgok(int lvl)
{
return dbgflg[lvl];
}
#if DEBUG || _USE_ZPRT_
#define XVERBOSE 1
#define dbgprt(_lvl,_fmt...) \
do { \
if (! dbgok(_lvl)) \
break; \
int sverr = errno; \
printf(_fmt); \
errno = sverr; \
} while (0)
#define inline_nodebug /**/
#else
#define XVERBOSE 0
#define inline_nodebug inline
#define dbgprt(_fmt...) \
do { } while (0)
#endif
#define sysfault(_fmt...) \
do { \
printf(_fmt); \
exit(1); \
} while (0)
#define RNGE(_val,_lo,_hi) \
(((_val) >= (_lo)) && ((_val) <= (_hi)))
#define PRTABLE(_val) \
RNGE(_val,0x20,0x7E) ? (_val) : '.'
#define CLOSEME(_fd) \
do { \
if (_fd < 0) \
break; \
dbgprt(ZPXHOWB64,"CLOSEME: fd=%d (from %d)\n",_fd,__LINE__); \
close(_fd); \
_fd = -1; \
} while (0)
#define FREEME(_ptr) \
do { \
dbgprt(ZPXHOWB64,"FREEME: ptr=%p (from %d)\n",_ptr,__LINE__); \
free(_ptr); \
_ptr = NULL; \
} while (0)
#endif
FILE: dbgcom.c
// dbgcom.c -- tracing setup
#include <dbgcom.h>
struct dbgdef {
int dbg_lvl;
const char *dbg_sym;
};
#define _ZPXDEF(_sym) \
{ .dbg_lvl = _sym, .dbg_sym = #_sym },
struct dbgdef dbgdef[] = {
ZPXHOWALL(_ZPXDEF)
{ .dbg_sym = NULL }
};
void __attribute__((constructor))
dbginit(void)
{
struct dbgdef *dbg = dbgdef;
for (; dbg->dbg_sym != NULL; ++dbg) {
char *cp = getenv(dbg->dbg_sym);
if (cp == NULL)
continue;
if (! atoi(cp))
continue;
dbgflg[dbg->dbg_lvl] = 1;
dbgflg[ZPXHOWANY] = 1;
}
}
Related
How to Combine 2 Struct arrays in C
iv tried a lot of solutions to try to get this working (i.e using memcpy etc) I cant seem to find the issue, depending on what I try I either end up with gibberish or SEGV iv spent a lot of time already googling and trying different ways, i still cant figure out why the arrays won't combine successfully #include <stdio.h> #include <stdint.h> #include <dirent.h> #include <sys/stat.h> #include <fcntl.h> #include <sys/syscall.h> #include <unistd.h> #define log_info printf typedef struct { char* name; //size_t size; } entry_t; /* qsort struct comparison function (C-string field) */ static int struct_cmp_by_name(const void* a, const void* b) { entry_t* ia = (entry_t*)a; entry_t* ib = (entry_t*)b; return strcmp(ia->name, ib->name); /* strcmp functions works exactly as expected from comparison function */ } entry_t* get_item_entries(const char* dirpath, int* count) { struct dirent* dent; char buffer[512]; // fixed buffer int dfd = 0, n, r = 1; // item counter, rounds to loop entry_t* p = NULL; // we fill this struct with items loop: n = 0; printf("loop: %d, count:%d\n", r, *count); // try to open dir dfd = open(dirpath, O_RDONLY, 0); if (dfd < 0) { printf("Invalid directory. (%s)\n", dirpath); *count = -1; return NULL; } else { printf("open(%s)\n", dirpath); } memset(buffer, 0, sizeof(buffer)); while (syscall(SYS_getdents, dfd, buffer, sizeof(buffer)) != 0) { dent = (struct dirent*)buffer; while (dent->d_fileno) { // skip `.` and `..` if (!strncmp(dent->d_name, "..", 2) || !strncmp(dent->d_name, ".", 1)) goto skip_dent; // deal with filtering outside of this function, we just skip .., . switch (r) { // first round: just count items case 1: { // skip special cases if (dent->d_fileno == 0) goto skip_dent; break; } // second round: store filenames case 0: p[n].name = strdup(dent->d_name); break; } n++; skip_dent: dent = (struct dirent*)((void*)dent + dent->d_reclen); if (dent == (void*)&buffer[512]) break; // refill buffer } memset(buffer, 0, sizeof(buffer)); } close(dfd); // on first round, calloc for our list if (!p) { // now n holds total item count, note it p = calloc(n, sizeof(entry_t)); *count = n; } // first round passed, loop r--; if (!r) goto loop; // report count printf("%d items at %p, from 1-%d\n", *count, (void*)p, *count); /* resort using custom comparision function */ qsort(p, *count, sizeof(entry_t), struct_cmp_by_name); // report items //for (int i = 0; i < num; ++i) log_error( "%s", p[i].name); return p; } int main(int argc, char* argv[]) { int HDD_count = -1; uint32_t total = -1; int ext_count = -1; entry_t* e = NULL; entry_t *HDD = get_item_entries("/mnt/f/n", &HDD_count); entry_t* ext = get_item_entries("/mnt/f/dls", &ext_count); total = ext_count + HDD_count; e = (entry_t*)malloc(sizeof *e * total); if (e != NULL) { for (int i = 1; i < HDD_count; i++) { log_info("HDD[%i].name %s\n", i, HDD[i].name); e[i].name = strdup(HDD[i].name); } for (int i = 1; i < ext_count; i++) { log_info("ext[%i].name %s\n", i, ext[i].name); e[i + HDD_count].name = strdup(ext[i].name); } } else printf("Failed to Allocate the Array"); char tmp[256]; int i = 1, j; for(j = 1; j <= total; j++) { snprintf(&tmp[0], 255, "%s", e[ j].name); log_info("%i:%s\n", j , tmp); } return 0; }
Here is a rewrite of a snippet of main() that I mentioned in my comment above: #define CHECK(p, msg) if(!(p)) { printf("%s:%d: %s", __FILE__, __LINE__, msg); return 1;} ... entry_t *HDD = get_item_entries("/mnt/f/n", &HDD_count); CHECK(HDD, "HDD failed to get entries"); entry_t *ext = get_item_entries("/mnt/f/dls", &ext_count); CHECK(ext, "ext failed to get entries"); uint32_t total = HDD_count + ext_count; entry_t *e = malloc(total * sizeof(*e)); CHECK(e, "malloc failed"); for(int i = 0; i < HDD_count; i++) { log_info("HDD[%i].name %s\n", i, HDD[i].name); e[i].name = strdup(HDD[i].name); } // write a function instead of duplicating code? for (int i = 0; i < ext_count; i++) { log_info("ext[%i].name %s\n", i, ext[i].name); e[HDD_count + i].name = strdup(ext[i].name); } It looks like a short lived program, but I would still free the values from strdup() and e itself.
Segmentation fault while comparing elements in a dynamically allocated array
This program tries to simulate FIFO and LRU page replacement. I am trying to implement a simple queue using a dynamically allocated array for the FIFO queue. I want the "page" to be stored in the array. #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/types.h> #include <sys/stat.h> #include <unistd.h> /* * Some compile-time constants. */ #define REPLACE_NONE 0 #define REPLACE_FIFO 1 #define REPLACE_LRU 2 #define REPLACE_SECONDCHANCE 3 #define REPLACE_OPTIMAL 4 #define TRUE 1 #define FALSE 0 #define PROGRESS_BAR_WIDTH 60 #define MAX_LINE_LEN 100 /* * Some function prototypes to keep the compiler happy. */ int setup(void); int teardown(void); int output_report(void); long resolve_address(long, int); void error_resolve_address(long, int); /* * Variables used to keep track of the number of memory-system events * that are simulated. */ int page_faults = 0; int mem_refs = 0; int swap_outs = 0; int swap_ins = 0; /* * Page-table information. You may want to modify this in order to * implement schemes such as SECONDCHANCE. However, you are not required * to do so. */ struct page_table_entry *page_table = NULL; struct page_table_entry { long page_num; int dirty; int free; }; /* * These global variables will be set in the main() function. The default * values here are non-sensical, but it is safer to zero out a variable * rather than trust to random data that might be stored in it -- this * helps with debugging (i.e., eliminates a possible source of randomness * in misbehaving programs). */ int size_of_frame = 0; /* power of 2 */ int size_of_memory = 0; /* number of frames */ int page_replacement_scheme = REPLACE_NONE; long *queue; void add_end(long page_num){ for(int i=0; i<size_of_memory; i++){ if(queue[i] == NULL){ queue[i] = page_num; break; } } } long peek_front(){ return queue[0]; } void remove_front(){ for(int i=0; i<size_of_memory; i++){ queue[i] = queue[i+1]; } } // typedef struct page_in_queue page_in_queue; // struct page_in_queue { // long page_num; // page_in_queue *next; // }; // page_in_queue *new_page(){ // page_in_queue *new_page; // new_page = (page_in_queue *) malloc(sizeof(page_in_queue)); // new_page->next = NULL; // return new_page; // } // page_in_queue *add_end(page_in_queue *queue, page_in_queue *page){ // page_in_queue *curr; // if (queue == NULL) { // page->next = NULL; // return page; // } // for (curr = queue; curr->next != NULL; curr = curr->next); // curr->next = page; // page->next = NULL; // return queue; // } // page_in_queue *peek_front(page_in_queue *queue) { // return queue; // } // page_in_queue *remove_front(page_in_queue *queue){ // if (queue == NULL) { // return NULL; // } // page_in_queue *new_front_page = queue->next; // free(queue); // return new_front_page; // } long *list; void add(long page_num){ int i; for (i=0; i<size_of_memory; i++){ list[i] = list[i+1]; } list[i] = page_num; } long peek_least_used(){ return list[0]; } /* * Function to convert a logical address into its corresponding * physical address. The value returned by this function is the * physical address (or -1 if no physical address can exist for * the logical address given the current page-allocation state. */ long resolve_address(long logical, int memwrite) { int i; long page, frame; long offset; long mask = 0; long effective; /* Get the page and offset */ page = (logical >> size_of_frame); for (i=0; i<size_of_frame; i++) { mask = mask << 1; mask |= 1; } offset = logical & mask; if (page_replacement_scheme == 2){ add(page); } /* Find page in the inverted page table. */ frame = -1; for ( i = 0; i < size_of_memory; i++ ) { if (!page_table[i].free && page_table[i].page_num == page) { frame = i; break; } } /* If frame is not -1, then we can successfully resolve the * address and return the result. */ if (frame != -1) { effective = (frame << size_of_frame) | offset; return effective; } /* If we reach this point, there was a page fault. Find * a free frame. */ page_faults++; for ( i = 0; i < size_of_memory; i++) { if (page_table[i].free) { frame = i; break; } } // page_in_queue *temp_page; // page_in_queue *queue; long rem_page; /* If we found a free frame, then patch up the * page table entry and compute the effective * address. Otherwise return -1. */ if (frame != -1) { page_table[frame].page_num = page; page_table[i].free = FALSE; swap_ins++; if (page_replacement_scheme == 1){ // temp_page = new_page(); // temp_page->page_num = page; add_end(page); } effective = (frame << size_of_frame) | offset; return effective; } else { if (page_replacement_scheme == 1){ rem_page = peek_front(); for ( i = 0; i < size_of_memory; i++){ if(page_table[i].page_num == rem_page){ page_table[i].page_num = page; page_table[i].free = FALSE; page_table[i].dirty = memwrite; swap_ins++; if(page_table[i].dirty == 1){ swap_outs++; } frame = i; break; } } remove_front(); effective = (frame << size_of_frame) | offset; return effective; } if (page_replacement_scheme == 2){ long temp = peek_least_used(); for ( i = 0; i < size_of_memory; i++){ if(page_table[i].page_num == temp){ page_table[i].page_num = page; page_table[i].free = FALSE; page_table[i].dirty = memwrite; swap_ins++; if(page_table[i].dirty == 1){ swap_outs++; } frame = i; break; } } effective = (frame << size_of_frame) | offset; return effective; } if (page_replacement_scheme == 3){ } } } /* * Super-simple progress bar. */ void display_progress(int percent) { int to_date = PROGRESS_BAR_WIDTH * percent / 100; static int last_to_date = 0; int i; if (last_to_date < to_date) { last_to_date = to_date; } else { return; } printf("Progress ["); for (i=0; i<to_date; i++) { printf("."); } for (; i<PROGRESS_BAR_WIDTH; i++) { printf(" "); } printf("] %3d%%", percent); printf("\r"); fflush(stdout); } int setup() { int i; page_table = (struct page_table_entry *)malloc( sizeof(struct page_table_entry) * size_of_memory ); if (page_table == NULL) { fprintf(stderr, "Simulator error: cannot allocate memory for page table.\n"); exit(1); } for (i=0; i<size_of_memory; i++) { page_table[i].free = TRUE; } return -1; } int teardown() { return -1; } void error_resolve_address(long a, int l) { fprintf(stderr, "\n"); fprintf(stderr, "Simulator error: cannot resolve address 0x%lx at line %d\n", a, l ); exit(1); } int output_report() { printf("\n"); printf("Memory references: %d\n", mem_refs); printf("Page faults: %d\n", page_faults); printf("Swap ins: %d\n", swap_ins); printf("Swap outs: %d\n", swap_outs); return -1; } int main(int argc, char **argv) { /* For working with command-line arguments. */ int i; char *s; /* For working with input file. */ FILE *infile = NULL; char *infile_name = NULL; struct stat infile_stat; int line_num = 0; int infile_size = 0; /* For processing each individual line in the input file. */ char buffer[MAX_LINE_LEN]; long addr; char addr_type; int is_write; /* For making visible the work being done by the simulator. */ int show_progress = FALSE; /* Process the command-line parameters. Note that the * REPLACE_OPTIMAL scheme is not required for A#3. */ for (i=1; i < argc; i++) { if (strncmp(argv[i], "--replace=", 9) == 0) { s = strstr(argv[i], "=") + 1; if (strcmp(s, "fifo") == 0) { page_replacement_scheme = REPLACE_FIFO; } else if (strcmp(s, "lru") == 0) { page_replacement_scheme = REPLACE_LRU; } else if (strcmp(s, "secondchance") == 0) { page_replacement_scheme = REPLACE_SECONDCHANCE; } else if (strcmp(s, "optimal") == 0) { page_replacement_scheme = REPLACE_OPTIMAL; } else { page_replacement_scheme = REPLACE_NONE; } } else if (strncmp(argv[i], "--file=", 7) == 0) { infile_name = strstr(argv[i], "=") + 1; } else if (strncmp(argv[i], "--framesize=", 12) == 0) { s = strstr(argv[i], "=") + 1; size_of_frame = atoi(s); } else if (strncmp(argv[i], "--numframes=", 12) == 0) { s = strstr(argv[i], "=") + 1; size_of_memory = atoi(s); if (page_replacement_scheme == 1){ queue = (long *)malloc(sizeof(long)*size_of_memory); } if (page_replacement_scheme == 2){ list = (long *)malloc(sizeof(long)*size_of_memory); } } else if (strcmp(argv[i], "--progress") == 0) { show_progress = TRUE; } } if (infile_name == NULL) { infile = stdin; } else if (stat(infile_name, &infile_stat) == 0) { infile_size = (int)(infile_stat.st_size); /* If this fails, infile will be null */ infile = fopen(infile_name, "r"); } if (page_replacement_scheme == REPLACE_NONE || size_of_frame <= 0 || size_of_memory <= 0 || infile == NULL) { fprintf(stderr, "usage: %s --framesize=<m> --numframes=<n>", argv[0]); fprintf(stderr, " --replace={fifo|lru|optimal} [--file=<filename>]\n"); exit(1); } setup(); while (fgets(buffer, MAX_LINE_LEN-1, infile)) { line_num++; if (strstr(buffer, ":")) { sscanf(buffer, "%c: %lx", &addr_type, &addr); if (addr_type == 'W') { is_write = TRUE; } else { is_write = FALSE; } if (resolve_address(addr, is_write) == -1) { error_resolve_address(addr, line_num); } mem_refs++; } if (show_progress) { display_progress(ftell(infile) * 100 / infile_size); } } teardown(); output_report(); fclose(infile); exit(0); } The file is saved as virtmem.c. This is the makefile: # # "makefile" for the virtual-memory simulation. # CC=gcc CFLAGS=-c -Wall -g all: virtmem virtmem.o: virtmem.c $(CC) $(CFLAGS) virtmem.c virtmem: virtmem.o $(CC) virtmem.o -o virtmem clean: rm -rf *.o virtmem After running the "make" command, I run the executable with these inputs ./virtmem --framesize=12 --numframes=100 --replace=fifo --file=traces/ls_out.txt --progress But it is giving a segmentation fault at the conditional "if(queue[i] == NULL)", saying the memory location cannot be accessed. The gdb output is as follows: Program received signal SIGSEGV, Segmentation fault. 0x0000555555554bea in add_end (page_num=34158723704) at virtmem.c:80 80 if(queue[i] == (long)0){ (gdb) print queue[i] Cannot access memory at address 0x0 (gdb)
How to get rid of unresolved external errors while trying to decode audio using ffmpeg
I am trying to decode a audio file using ffmpeg, while I am doing this I am getting many unresolved external errors. I am new to ffmpeg libraries, any suggestion for the problem would be a great help. Thank you. void audioDecode(char* filename) { FILE *file; AVFormatContext *audioInputFormatContext; AVInputFormat *audioInputFormat = NULL; AVCodec *audioCodec; AVCodecContext *audioCodecContext; av_register_all(); char *audioInputDeviceName = filename; int ret; int audioIndex = 0; AVPacket pkt; av_init_packet(&pkt); avformat_network_init(); audioInputFormatContext = avformat_alloc_context(); ret = avformat_open_input(&audioInputFormatContext, audioInputDeviceName, audioInputFormat, NULL); if (ret == 0) { ret = avformat_find_stream_info(audioInputFormatContext, 0); if (ret >= 0) { for (int i = 0; i < audioInputFormatContext->nb_streams; i++) { if (audioInputFormatContext->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) { audioIndex = i; break; } } audioCodec = avcodec_find_decoder(audioInputFormatContext->streams[audioIndex]->codecpar->codec_id); audioCodecContext = avcodec_alloc_context3(audioCodec); avcodec_parameters_to_context(audioCodecContext, audioInputFormatContext->streams[audioIndex]->codecpar); if (avcodec_open2(audioCodecContext, audioCodec, NULL) >= 0) { ret = av_read_frame(audioInputFormatContext, &pkt); AVPacket encodePacket; AVFrame* decodeFrame = av_frame_alloc(); int dec_got_frame = 0; if (ret == 0) { ret = avcodec_send_packet(audioCodecContext, &pkt); if (ret < 0) printf("Error"); } ret = avcodec_receive_frame(audioCodecContext, decodeFrame); if (ret >= 0) dec_got_frame = 1; if (dec_got_frame) { fopen_s(&file, filename, "wb"); fwrite(pkt.data, 1, pkt.size, file); fclose(file); } av_frame_free(&decodeFrame); } } } avformat_close_input(&audioInputFormatContext); avcodec_free_context(&audioCodecContext); av_packet_unref(&pkt); }
I'm just going to assume that you've already connected to the stream source and have the codec context by what you've mentioned in the comments. These are snippets from my own project decoding the audio frames. Decode the audio packet: void FFMPEG::process_audio_packet(AVPacket *pkt) { int got; avcodec_decode_audio4(aud_stream.context, aud_stream.frame, &got, pkt); if (got) Audio.add_av_frame(aud_stream.frame); } Process the completed frame and extract a stereo 16 bit signed buffer: void AudioManager::add_av_frame(AVFrame *frame) { int nsamples = frame->nb_samples; int sample_rate = frame->sample_rate; int channels = frame->channels; AVSampleFormat format = (AVSampleFormat) frame->format; bool planar = av_sample_fmt_is_planar(format) == 1; int64_t pts = av_frame_get_best_effort_timestamp(frame); //double ftime; /*if (ffmpeg.vid_stream.stream_id != -1) ftime = av_q2d(ffmpeg.aud_stream.context->time_base) * pts; else ftime = av_q2d(ffmpeg.vid_stream.context->time_base) * pts;*/ AudioBuffer *buffer = NULL; if (planar) { // handle planar audio frames /* * PLANAR frames conversion * ------------------------ */ if (channels == 1) { // MONO //LOGD("Processing PLANAR MONO"); /* * MONO */ if (format == AV_SAMPLE_FMT_S16P) { // 16 bit signed if ((buffer = alloc_buffer(frame))) { // allocated okay? short *channel = (short*)frame->data[0]; short *buff = buffer->data; for (int c = 0; c < nsamples; c++) { *buff++ = *channel; *buff++ = *channel++; } queue_new_buffer(buffer); } return; } if (format == AV_SAMPLE_FMT_S32P) { // 32 bit signed if ((buffer = alloc_buffer(frame))) { // allocated okay? int32_t *channel = (int32_t*)frame->data[0]; short *buff = buffer->data; for (int c = 0; c < nsamples; c++) { int16_t s = (int16_t) (*channel++ >> 16); *buff++ = s; *buff++ = s; } queue_new_buffer(buffer); } return; } if (format == AV_SAMPLE_FMT_U8P) { // 8 bit unsigned if ((buffer = alloc_buffer(frame))) { // allocated okay? uint8_t *channel = (uint8_t*)frame->data[0]; short *buff = buffer->data; for (int c = 0; c < nsamples; c++) { int16_t s = ((int16_t)(*channel++ - 128) << 8); *buff++ = s; *buff++ = s; } queue_new_buffer(buffer); } } return; // scrap if no audio buffer (highly unlikely) } else if (channels == 2) { // STEREO //LOGD("Processing PLANAR STEREO"); /* * STEREO */ if (format == AV_SAMPLE_FMT_S16P) { // 16 bit signed if ((buffer = alloc_buffer(frame))) { // allocated okay short *channel1 = (short*)frame->data[0]; short *channel2 = (short*)frame->data[1]; short *buff = buffer->data; for (int c = 0; c < nsamples; c++) { *buff++ = *channel1++; *buff++ = *channel2++; } queue_new_buffer(buffer); } return; } if (format == AV_SAMPLE_FMT_S32P) { // 32 bit signed if ((buffer = alloc_buffer(frame))) { // allocated okay? int32_t *channel1 = (int32_t*)frame->data[0]; int32_t *channel2 = (int32_t*)frame->data[1]; short *buff = buffer->data; for (int c = 0; c < nsamples; c++) { int16_t s1 = (int16_t) (*channel1++ >> 16); int16_t s2 = (int16_t) (*channel2++ >> 16); *buff++ = s1; *buff++ = s2; } queue_new_buffer(buffer); } return; } if (format == AV_SAMPLE_FMT_U8P) { // 8 bit unsigned if ((buffer = alloc_buffer(frame))) { // allocated okay? uint8_t *channel1 = (uint8_t*)frame->data[0]; uint8_t *channel2 = (uint8_t*)frame->data[1]; short *buff = buffer->data; for (int c = 0; c < nsamples; c++) { int16_t s1 = ((int16_t)(*channel1++ - 128) << 8); int16_t s2 = ((int16_t)(*channel2++ - 128) << 8); *buff++ = s1; *buff++ = s2; } queue_new_buffer(buffer); } } return; } // TODO: Handle more channels at a later date } else { // handle non-planar audio frames /* * INTERLEAVED conversion * ---------------------- */ } } Process the audio buffer: void AudioManager::queue_new_buffer(AudioBuffer *buffer) { if (buffer) { // valid buffer // apply volume gain (only working with stereo) if (volume != 100) { short *data = buffer->data; int num_samples = buffer->nsamples << 1; while (num_samples--) { long sample = ((long)*data * volume) / 100; if (sample < -32768) sample = -32768; if (sample > 32767) sample = 32767; *data++ = (short)sample; } } // add buffer to queue buffer->used = true; double pts_start = get_pts_start_time(); decode_pos = (++decode_pos) % MAX_AUD_BUFFERS; if (decode_pos == playback_pos) playback_pos = (++playback_pos) % MAX_AUD_BUFFERS; if (ffmpeg.vid_stream.stream_id == -1 && pts_start < 0.0) { set_pts_start_time(buffer->frame_time); set_sys_start_time(Display.get_current_render_time()); LOGD("START TIME FROM AUDIO STREAM..."); } //LOGI("Audio buffer queued %d (%d)", decode_pos, playback_pos); } }
Writing improper number of frames using PortAudio?
Running my program, I appear to not be writing the correct amount of frames according to the index. $ ./test Now recording!! Please speak into the microphone. index = 0 Writing to: test.flac audio.h: #include <stdint.h> #include <string.h> typedef struct { uint32_t duration; uint16_t format_type; uint16_t number_of_channels; uint32_t sample_rate; uint32_t frameIndex; /* Index into sample array. */ uint32_t maxFrameIndex; char* recordedSamples; } AudioData; int recordFLAC(AudioData* data, const char *fileName); AudioData* initAudioData(uint32_t sample_rate, uint16_t channels, uint32_t duration); capture.c: #include <stdio.h> #include <stdlib.h> #include <portaudio.h> #include <sndfile.h> #include "audio.h" AudioData* initAudioData(uint32_t sample_rate, uint16_t channels, uint32_t duration) { AudioData* data = malloc(sizeof(*data)); if (!data) return NULL; data->duration = duration; data->format_type = 1; data->number_of_channels = channels; data->sample_rate = sample_rate; data->frameIndex = 0; data->maxFrameIndex = sample_rate * duration; data->recordedSamples = malloc(sizeof(data->maxFrameIndex)); if(!data->maxFrameIndex) return NULL; return data; } static int recordCallback(const void *inputBuffer, void *outputBuffer, unsigned long frameCount, const PaStreamCallbackTimeInfo* timeInfo, PaStreamCallbackFlags statusFlags, void *userData) { AudioData* data = (AudioData*)userData; const char* buffer_ptr = (const char*)inputBuffer; char* index_ptr = &data->recordedSamples[data->frameIndex]; (void) outputBuffer; (void) timeInfo; (void) statusFlags; long framesToCalc; long i; int finished; unsigned long framesLeft = data->maxFrameIndex - data->frameIndex; if(framesLeft < frameCount){ framesToCalc = framesLeft; finished = paComplete; }else{ framesToCalc = frameCount; finished = paContinue; } if(!inputBuffer){ for(i = 0; i < framesToCalc; i++){ *index_ptr++ = 0; } }else{ for(i = 0; i < framesToCalc; i++){ *index_ptr++ = *buffer_ptr++; } } data->frameIndex += framesToCalc; return finished; } int recordFLAC(AudioData* data, const char *fileName) { PaStreamParameters inputParameters; PaStream* stream; int err = 0; int totalFrames = data->maxFrameIndex; int numSamples; int numBytes; char max, val; double average; numSamples = totalFrames * data->number_of_channels; numBytes = numSamples; data->recordedSamples = malloc(numBytes); if(!data->recordedSamples) { printf("Could not allocate record array.\n"); goto done; } for(int i = 0; i < numSamples; i++) data->recordedSamples[i] = 0; if((err = Pa_Initialize())) goto done; inputParameters.device = Pa_GetDefaultInputDevice(); /* default input device */ if (inputParameters.device == paNoDevice) { fprintf(stderr,"Error: No default input device.\n"); goto done; } inputParameters.channelCount = data->number_of_channels; /* stereo input */ inputParameters.sampleFormat = data->format_type; inputParameters.suggestedLatency = Pa_GetDeviceInfo(inputParameters.device)->defaultLowInputLatency; inputParameters.hostApiSpecificStreamInfo = NULL; /* Record some audio. -------------------------------------------- */ err = Pa_OpenStream(&stream, &inputParameters, NULL, data->sample_rate, paFramesPerBufferUnspecified, paClipOff, recordCallback, &data); if(err) goto done; if((err = Pa_StartStream(stream))) goto done; puts("Now recording!! Please speak into the microphone."); while((err = Pa_IsStreamActive(stream)) == 1) { Pa_Sleep(1000); printf("index = %d\n", data->frameIndex); } if( err < 0 ) goto done; err = Pa_CloseStream(stream); if(err) goto done; /* Measure maximum peak amplitude. */ max = 0; average = 0.0; for(int i = 0; i < numSamples; i++) { val = data->recordedSamples[i]; val = abs(val); if( val > max ) { max = val; } average += val; } average /= (double)numSamples; done: Pa_Terminate(); if(err) { fprintf(stderr, "An error occured while using the portaudio stream\n"); fprintf(stderr, "Error number: %d\n", err); fprintf(stderr, "Error message: %s\n", Pa_GetErrorText(err)); err = 1; /* Always return 0 or 1, but no other return codes. */ } else { SF_INFO sfinfo; sfinfo.channels = 1; sfinfo.samplerate = data->sample_rate; sfinfo.format = SF_FORMAT_FLAC | SF_FORMAT_PCM_16; // open to file printf("Writing to: %s\n", fileName); SNDFILE * outfile = sf_open(fileName, SFM_WRITE, &sfinfo); if (!outfile) return -1; // prepare a 3 second long buffer (sine wave) const int size = data->sample_rate * 3; // write the entire buffer to the file sf_write_raw(outfile, data->recordedSamples, size); // force write to disk sf_write_sync(outfile); // don't forget to close the file sf_close(outfile); } return err; } I'm not quite sure where I am going wrong, I know I need to be writing more frames. Any suggestions?
There seems to be something wrong with your assumptions about the sample format. In the callback you are using char * (single bytes) for the sample format, but in your libsndfile call you're opening a 16 bit file with SF_FORMAT_PCM_16. This is not so good: data->format_type = 1; I recommend using one of the symbolic constants in the PortAudio library for sample formatting. Maybe you want a 16 bit one? And if so, you want to be using short* not char* in the PA callback. Finally, if your channel count is not 1, the copy loops are incorrect: for(i = 0; i < framesToCalc; i++){ *index_ptr++ = 0; } A "frame" contains data for all channels, so for example, if it's a stereo input your iteration needs to deal with both left and right channels like this: for(i = 0; i < framesToCalc; i++){ *index_ptr++ = 0; // left *index_ptr++ = 0; // right } Same for the other loops.
Visual Studio Command Prompt C/C++ Compiling Error " Error Code C2143: syntax error : missing ')' before ';' "
I'm new to writing code and have spent hours trying to solve this error. The script is for a memory scanner. Here is the code I have. The error is in line 147. It keeps giving me error C2143 missing ')' before ' ; ' ... #include <windows.h> #include <stdio.h> #define IS_IN_SEARCH(mb,offset) (mb->searchmask[(offset)/8] & (1<<((offset)%8))); #define REMOVE_FROM_SEARCH(mb,offset) (mb->searchmask[(offset)/8] &= ~ (1<<((offset)%8)); typedef struct MEMBLOCK { HANDLE hProc; unsigned char *addr; int size; unsigned char *buffer; unsigned char *searchmask; int matches; int data_size; struct MEMBLOCK *next; }MEMBLOCK; typedef enum { COND_UNCONDITIONAL, COND_EQUALS, COND_INCREASED, COND_DECREASED, }SEARCH_CONDITION; MEMBLOCK* create_memblock (HANDLE hProc, MEMORY_BASIC_INFORMATION *meminfo, int data_size) { MEMBLOCK *mb = malloc (sizeof(MEMBLOCK)); if (mb) { mb->hProc = hProc; mb->addr = meminfo->BaseAddress; mb->size = meminfo->RegionSize; mb->buffer = malloc (meminfo->RegionSize); mb->searchmask = malloc (meminfo->RegionSize/8); memset (mb->searchmask, 0xff, meminfo->RegionSize/8); mb->matches = meminfo->RegionSize; mb->data_size = data_size; mb->next = NULL; } return mb; } void free_memblock (MEMBLOCK *mb) { if (mb) { if (mb->buffer); { free (mb->buffer); } if (mb->searchmask) { free (mb->searchmask); } free (mb); } } void update_memblock (MEMBLOCK *mb, SEARCH_CONDITION condition, unsigned int val) { static unsigned char tempbuf[128*1024]; unsigned int bytes_left; unsigned int total_read; unsigned int bytes_to_read; unsigned int bytes_read; if (mb->matches > 0) { bytes_left = mb->size; total_read = 0; mb->matches = 0; while (bytes_left) { bytes_to_read = (bytes_left > sizeof(tempbuf)) ? sizeof(tempbuf) : bytes_left; ReadProcessMemory (mb->hProc, mb->addr + total_read, tempbuf, bytes_to_read, (DWORD*)&bytes_read); if (bytes_read != bytes_to_read) break; if (condition == COND_UNCONDITIONAL) { memset (mb->searchmask + (total_read/8), 0xff, bytes_read/8); mb->matches += bytes_read; } else { unsigned int offset; for (offset = 0; offset < bytes_read; offset += mb->data_size) { if IS_IN_SEARCH(mb,(total_read+offset)) { BOOL is_match = FALSE; unsigned int temp_val; unsigned int prev_val = 0; switch (mb->data_size) { case 1: temp_val = tempbuf[offset]; prev_val = *((unsigned char*)&mb->buffer[total_read+offset]); break; case 2: temp_val = *((unsigned short*)&tempbuf[offset]); prev_val = *((unsigned short*)&mb->buffer[total_read+offset]); break; case 4: default: temp_val = *((unsigned int*)&tempbuf[offset]); prev_val = *((unsigned int*)&mb->buffer[total_read+offset]); break; } switch (condition) { case COND_EQUALS: is_match = (temp_val == val); break; case COND_INCREASED: is_match = (temp_val > prev_val); break; case COND_DECREASED: is_match = (temp_val < prev_val); break; default: break; } if (is_match) { mb->matches++; } else { 147===*? REMOVE_FROM_SEARCH(mb,(total_read+offset)); ?*===147 } } } } memcpy (mb->buffer + total_read, tempbuf, bytes_read); bytes_left -= bytes_read; total_read += bytes_read; } mb->size = total_read; } } MEMBLOCK* create_scan (unsigned int pid, int data_size) { MEMBLOCK *mb_list = NULL; MEMORY_BASIC_INFORMATION meminfo; unsigned char *addr = 0; HANDLE hProc = OpenProcess (PROCESS_ALL_ACCESS, FALSE, pid); if (hProc) { while (1) { if (VirtualQueryEx (hProc, addr, &meminfo, sizeof(meminfo)) == 0) { break; } #define WRITABLE (PAGE_READWRITE | PAGE_WRITECOPY | PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY) if ((meminfo.State & MEM_COMMIT) && (meminfo.Protect & WRITABLE)) { MEMBLOCK *mb = create_memblock (hProc, &meminfo, data_size); if (mb) { mb->next = mb_list; mb_list = mb; } } addr = (unsigned char*)meminfo.BaseAddress + meminfo.RegionSize; } } return mb_list; } void free_scan (MEMBLOCK *mb_list) { CloseHandle (mb_list->hProc); while (mb_list) { MEMBLOCK *mb = mb_list; mb_list = mb_list->next; free_memblock (mb); } } void update_scan (MEMBLOCK *mb_list, SEARCH_CONDITION condition, unsigned int val) { MEMBLOCK *mb = mb_list; while (mb) { update_memblock (mb, condition, val); mb = mb->next; } } void dump_scan_info (MEMBLOCK *mb_list) { MEMBLOCK *mb = mb_list; while (mb) { int i; printf ("0x%08x %d\r\n", mb->addr, mb->size); for (i = 0; i < mb->size; i++) { printf ("%02x", mb->buffer[i]); } printf ("\r\n"); mb = mb->next; } } void poke (HANDLE hProc, int data_size, unsigned int addr, unsigned int val) { if (WriteProcessMemory (hProc, (void*)addr, &val, data_size, NULL) == 0) { printf ("poke failed\r\n"); } } unsigned int peek (HANDLE hProc, int data_size, unsigned int addr) { unsigned int val = 0; if (ReadProcessMemory (hProc, (void*)addr, &val, data_size, NULL) == 0) { printf ("peek failed\r\n"); } return val; } void print_matches (MEMBLOCK *mb_list) { unsigned int offset; MEMBLOCK *mb = mb_list; while (mb) { for (offset = 0; offset < mb->size; offset += mb->data_size) { if IS_IN_SEARCH(mb,offset) { unsigned int val = peek (mb->hProc, mb->data_size, (unsigned int)mb->addr + offset); printf ("0x%08x: 0x%08x (%d) \r\n", mb->addr + offset, val, val); } } mb = mb->next; } } int get_match_count (MEMBLOCK *mb_list) { MEMBLOCK *mb = mb_list; int count = 0; while (mb) { count += mb->matches; mb = mb->next; } return count; } unsigned int str2int (char *s) { int base = 10; if (s[0] == '0' && s[1] == 'x') { base = 16; s += 2; } return strtoul (s, NULL, base); } MEMBLOCK* ui_new_scan(void) { MEMBLOCK *scan = NULL; DWORD pid; int data_size; unsigned int start_val; SEARCH_CONDITION start_cond; char s[20]; while(1) { printf ("\r\nEnter the pid: "); fgets (s,sizeof(s),stdin); pid = str2int (s); printf ("\r\nEnter the data size: "); fgets (s,sizeof(s),stdin); data_size = str2int (s); printf ("\r\nEnter the start value, or 'u' for unknown: "); fgets (s,sizeof(s),stdin); if (s[0] == 'u') { start_cond = COND_UNCONDITIONAL; start_val = 0; } else { start_cond = COND_EQUALS; start_val = str2int (s); } scan = create_scan (pid, data_size); if (scan) break; print ("\r\nInvalid scan"); } update_scan (scan, start_cond, start_val); printf ("\r\n%d matches found\r\n", get_match_count(scan)); return scan; } void ui_poke (HANDLE hProc, int data_size) { unsigned int addr; unsigned int val; char s[20]; printf ("Enter the address: "); fgets (s,sizeof(s),stdin); addr = str2int (s); printf ("\r\nEnter the value: "); fgets (s,sizeof(s),stdin); val = str2int (s); printf ("\r\n"); poke (hProc, data_size, addr, val); } void ui_run_scan(void) { unsigned int val; char s[20]; MEMBLOCK *scan; scan = ui_new_scan(); while (1) { printf ("\r\nEnter the next value or"); printf ("\r\n[i] increased"); printf ("\r\n[d] decreased"); printf ("\r\n[m] print matches"); printf ("\r\n[p] poke address"); printf ("\r\n[n] new scan"); printf ("\r\n[q] quit\r\n"); fgets(s,sizeof(s),stdin); printf ("\r\n"); switch (s[0]) { case 'i': update_scan (scan, COND_INCREASED, 0); printf ("%d matches found\r\n", get_match_count(scan)); break; case 'd': update_scan (scan, COND_DECREASED, 0); printf ("%d matches found\r\n", get_match_count(scan)); break; case 'm': print_matches (scan); break; case 'p': ui_poke (scan->hProc, scan->data_size); break; case 'n': free_scan (scan); scan = ui_new_scan(); break; case 'q': free_scan (scan); return; default: val = str2int (s); update_scan (scan, COND_EQUALS, val); printf ("%d matches found\r\n", get_match_count(scan)); break; } } } int main (int argc, char *argv[]) { ui_run_scan(); return 0; }
#define IS_IN_SEARCH(mb,offset) (mb->searchmask[(offset)/8] & (1<<((offset)%8))); #define REMOVE_FROM_SEARCH(mb,offset) (mb->searchmask[(offset)/8] &= ~ (1<<((offset)%8)); Should be #define IS_IN_SEARCH(mb,offset) (mb->searchmask[(offset)/8] & (1<<((offset)%8))) #define REMOVE_FROM_SEARCH(mb,offset) (mb->searchmask[(offset)/8] &= ~ (1<<((offset)%8)) Or, better yet, make them functions to avoid the terrible macro pitfalls: static int is_in_search(MEMBLOCK* mb, unsigned int offset){ return mb->searchmask[offset/8] & (1<<(offset%8)); } static void remove_from_search(MEMBLOCK *mb, unsigned int offset){ mb->searchmask[offset/8] &= ~ (1<<(offset%8)); }
Change: #define REMOVE_FROM_SEARCH(mb,offset) \ (mb->searchmask[(offset)/8] &= ~ (1<<((offset)%8)); to #define REMOVE_FROM_SEARCH(mb,offset) \ (mb->searchmask[(offset)/8] &= ~ (1<<((offset)%8))) specifically, there is a missing closing parenthesis. Also, the semicolons are not needed and typically omitted. This type of error is one reason we often favor inline functions over macros :)
#defines don't have a ; at the end. It's treated as an error by the compiler.