Related
I have a code that produce PNG file (using libpng).
I can open these files with EOG (Eye Of Gnome) but with GIMP, imagemagic and others I have an error.
Exiftool tells me that png file is truncated, but I don't see where. On EOG everything is ok.
The code:
int savepng(const char *name, fits *fit, uint32_t bytes_per_sample,
gboolean is_colour) {
int32_t ret = -1;
png_structp png_ptr;
png_infop info_ptr;
const uint32_t width = fit->rx;
const uint32_t height = fit->ry;
char *filename = strdup(name);
if (!ends_with(filename, ".png")) {
filename = str_append(&filename, ".png");
}
FILE *p_png_file = g_fopen(name, "wb");
if (p_png_file == NULL) {
return ret;
}
/* Create and initialize the png_struct with the desired error handler
* functions. If you want to use the default stderr and longjump method,
* you can supply NULL for the last three parameters. We also check that
* the library version is compatible with the one used at compile time,
* in case we are using dynamically linked libraries. REQUIRED.
*/
png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
if (png_ptr == NULL) {
fclose(p_png_file);
return ret;
}
/* Allocate/initialize the image information data. REQUIRED */
info_ptr = png_create_info_struct(png_ptr);
if (info_ptr == NULL) {
fclose(p_png_file);
png_destroy_write_struct(&png_ptr, NULL);
return ret;
}
/* Set error handling. REQUIRED if you aren't supplying your own
* error handling functions in the png_create_write_struct() call.
*/
if (setjmp(png_jmpbuf(png_ptr))) {
/* If we get here, we had a problem writing the file */
fclose(p_png_file);
png_destroy_write_struct(&png_ptr, &info_ptr);
return ret;
}
/* Set up the output control if you are using standard C streams */
png_init_io(png_ptr, p_png_file);
/* Set the image information here. Width and height are up to 2^31,
* bit_depth is one of 1, 2, 4, 8, or 16, but valid values also depend on
* the color_type selected. color_type is one of PNG_COLOR_TYPE_GRAY,
* PNG_COLOR_TYPE_GRAY_ALPHA, PNG_COLOR_TYPE_PALETTE, PNG_COLOR_TYPE_RGB,
* or PNG_COLOR_TYPE_RGB_ALPHA. interlace is either PNG_INTERLACE_NONE or
* PNG_INTERLACE_ADAM7, and the compression_type and filter_type MUST
* currently be PNG_COMPRESSION_TYPE_BASE and PNG_FILTER_TYPE_BASE. REQUIRED
*/
if (is_colour) {
png_set_IHDR(png_ptr, info_ptr, width, height, bytes_per_sample * 8,
PNG_COLOR_TYPE_RGB,
PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE,
PNG_FILTER_TYPE_DEFAULT);
uint32_t profile_len;
const unsigned char *profile = get_sRGB_profile_data(&profile_len);
if (profile_len > 0) {
png_set_iCCP(png_ptr, info_ptr, *name ? name : "icc", 0, (png_const_bytep) profile, profile_len);
}
} else {
png_set_IHDR(png_ptr, info_ptr, width, height, bytes_per_sample * 8,
PNG_COLOR_TYPE_GRAY,
PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE,
PNG_FILTER_TYPE_DEFAULT);
}
/* Write the file header information. REQUIRED */
png_write_info(png_ptr, info_ptr);
png_bytep *row_pointers = malloc((size_t) height * sizeof(png_bytep));
int samples_per_pixel;
if (is_colour) {
samples_per_pixel = 3;
} else {
samples_per_pixel = 1;
}
if (bytes_per_sample == 2) {
/* swap bytes of 16 bit files to most significant bit first */
png_set_swap(png_ptr);
WORD *data = convert_data(fit);
for (unsigned i = 0, j = height - 1; i < height; i++)
row_pointers[j--] = (png_bytep) ((uint16_t*) data + (size_t) samples_per_pixel * i * width);
} else {
uint8_t *data = convert_data8(fit);
for (unsigned i = 0, j = height - 1; i < height; i++)
row_pointers[j--] = (uint8_t*) data + (size_t) samples_per_pixel * i * width;
}
png_write_image(png_ptr, row_pointers);
/* Clean up after the write, and free any memory allocated */
png_destroy_write_struct(&png_ptr, &info_ptr);
/* Close the file */
fclose(p_png_file);
free(row_pointers);
free(filename);
return 0;
}
Could someone point me out my error? Software that can't read the image just display an error dialog. That's all. So it is difficult for me to know where is the error.
As proposed by #MarkSetchell, one line was missing:
/* Clean up after the write, and free any memory allocated */
png_write_end(png_ptr, info_ptr); // this line was missing
png_destroy_write_struct(&png_ptr, &info_ptr);
That's all.
Thank you.
I think that png_write_image() only writes the image row data, so various headers or elements of meta-data are missing. I normally use png_write_png() to write the whole file.
I've attached some code that definitely works for me, in that the output can be read by Gimp, etc. I don't claim it's production-quality ;)
int bitmap_write_png (const bitmap_t *bitmap, const char *path)
{
int ret = -1;
size_t x, y;
int pixel_size = 3;
int depth = 8;
FILE *fp = fopen (path, "wb");
if (fp)
{
ret = 0;
png_structp png_ptr = png_create_write_struct (PNG_LIBPNG_VER_STRING,
NULL, NULL, NULL);
png_infop info_ptr = info_ptr = png_create_info_struct (png_ptr);
png_set_IHDR (png_ptr,
info_ptr,
bitmap->width,
bitmap->height,
depth,
PNG_COLOR_TYPE_RGB,
PNG_INTERLACE_NONE,
PNG_COMPRESSION_TYPE_DEFAULT,
PNG_FILTER_TYPE_DEFAULT);
png_byte ** row_pointers = png_malloc (png_ptr,
bitmap->height * sizeof (png_byte *));
for (y = 0; y < bitmap->height; y++)
{
png_byte *row =
png_malloc (png_ptr, sizeof (uint8_t) * bitmap->width * pixel_size);
row_pointers[y] = row;
for (x = 0; x < bitmap->width; x++)
{
pixel_t *pixel = pixel_at_const (bitmap, x, y);
*row++ = pixel->red * 255;
*row++ = pixel->green * 255;
*row++ = pixel->blue * 255;
}
}
png_init_io (png_ptr, fp);
png_set_rows (png_ptr, info_ptr, row_pointers);
png_write_png (png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, NULL);
for (y = 0; y < bitmap->height; y++)
{
png_free (png_ptr, row_pointers[y]);
}
png_free (png_ptr, row_pointers);
close (fp);
}
else
{
ret = errno;
}
return ret;
}
I have an array of numbers which i want to compress and store in a file then decompress and put data in a buffer.
RAM->FILE compressing
FILE->RAM decompressing
I used LzmaEncode for compressing and then write compress buffer in a file.
lzmaencoder.c
int main(void){
int data[] = {1,2,3,4,5};
size_t src_len = sizeof(data);
const Byte * src = (Byte *) data;
size_t compressed_size = src_len*1.5;
Byte * compressed_data = malloc(compressed_size);
CLzmaEncProps props;
LzmaEncProps_Init(&props);
Byte header[LZMA_PROPS_SIZE];
size_t headerSize = LZMA_PROPS_SIZE;
// Call encoding function:
SRes res;
res = LzmaEncode(compressed_data, &compressed_size, src, src_len,
&props, header, &headerSize, 0, NULL, &g_Alloc, &g_Alloc);
if(res == SZ_OK){
FILE * file = fopen("lzma_file","wb");
fwrite(compressed_data, sizeof(Byte), compressed_size, file);
}
free(compressed_data);
return (0);
}
I read compress file and write data in a buffer, then use LzmaDecode for decompressing.
lzmadecoder.c
int main(int argc, char * argv[]){
// I know the original data size
size_t uncompress_size = 20;
Byte * uncompress = malloc(uncompress_size);
// open compressed file
size_t compress_size;
FILE * compress_file = fopen("lzma_file", "rb");
if(!compress_file){
printf("Error: can not open lzma_file file.");
}
// get compressed file size
fseek(compress_file, 0, SEEK_END);
compress_size = ftell(compress_file);
fseek(compress_file, 0, SEEK_SET);
Byte *compress_data = malloc(compress_size);
// put compressed file data on RAM
if(!fread(compress_data, sizeof(Byte), compress_size, compress_file)){
printf("Error: can not read lzma_file file.");
}
fclose(compress_file);
ELzmaStatus status;
// RAM->RAM decompressing
int res = LzmaDecode(uncompress, &uncompress_size,
compress_data, &compress_size,
compress_data, 5,
LZMA_FINISH_END, &status, &g_Alloc);
if(res==SZ_OK){
printf("SZ_OK!\n");
} else if(res==SZ_ERROR_DATA){
printf("SZ_ERROR_DATA!\n");
}
free(uncompress);
free(compress_data);
return (0);
}
but LzmaDecode return SZ_ERROR_DATA. I cant find my problem.
LZMA compression---------------- Version: 9.35
Use the Lib API generated by the project "lzma1900\C\Util\LzmaLib": LzmaCompress and LzmaUncompress.
int main()
{
Byte outProps[5];
size_t outPropsSize = 5; /* *outPropsSize must be = 5 */
int r =RawEncode(out,&tmpLen,bnInfo, len1,outProps,&outPropsSize);
Pkt init =RawDecode(out2,$outLen2, out, tmpLen, &outPropsSize);
return 0;
}
int RawEncode(char* out, int *ol, char *buf, uint32_t l, char* outProps, size_t* outPropsSize)
{
int res = 0;
m_l = 8;
int level = m_level; /* 0 <= level <= 9, default = 5 */
unsigned dictSize = 1 << 24; /* default = (1 << 24) */
int lc = 3; /* 0 <= lc <= 8, default = 3 */
int lp = 0; /* 0 <= lp <= 4, default = 0 */
int pb = 2; /* 0 <= pb <= 4, default = 2 */
int fb = 32; /* 5 <= fb <= 273, default = 32 */
int numThreads = 1; /* 1 or 2, default = 2 */
int r = LzmaCompress(out,ol,buf,l,outProps, outPropsSize, m_level, dictSize, lc, lp, pb, fb, 1);
olen = l;
return r;
}
void RawDecode(char* out, int* oLen, char* buf, int len, unsigned char* props, size_t* propsSize)
{
char out[outLen];
SizeT srcLen = pkt.first.len - 8;
int r = LzmaUncompress(out, oLen, buf, &len, props, *propsSize);
if(SZ_OK != r)
{
printf("LzmaUncompress error %d.", r);
delete [] tmp.second;
tmp.second = NULL;
}
}
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 4 years ago.
Improve this question
I'm a complete newbie in C and have an assignment that states I have to implement CRC-16 into a given UDP File Transfer solution. Given code is as follows:
#pragma comment(lib, "ws2_32.lib")
#include "stdafx.h"
#include <winsock2.h>
#include "ws2tcpip.h"
#include <stdio.h>
#define TARGET_IP "10.4.115.122"
//#define TARGET_IP "127.0.0.1"
#define BUFFERS_LEN 1024
#define SIZE_PACKET 10 // we can send up to 9 999 999 999 packets
#define HEADER_LEN (SIZE_PACKET + 5)
#define DATA_LEN (BUFFERS_LEN - HEADER_LEN)
//#define SENDER
#define END {getchar();return 0;}
#define RECEIVER
typedef struct Data
{
int size;
char *data;
}Data;
#ifdef SENDER
#define TARGET_PORT 5005
#define LOCAL_PORT 8888
#endif // SENDER
#ifdef RECEIVER
#define TARGET_PORT 8888
#define LOCAL_PORT 5005
#endif // RECEIVER
void InitWinsock()
{
WSADATA wsaData;
WSAStartup(MAKEWORD(2, 2), &wsaData);
}
void print(char *data, int size)
{
for (int i = 0; i < size; i++)
{
if (data[i] == '\0')
{
printf("\\0");
}
else
{
printf("%c", data[i]);
}
}
printf("\n");
}
void clearBuffer(char *buffer, int size)
{
/* Put NULL character on the array */
for (int i = 0; i < size; i++)
{
buffer[i] = '\0';
}
}
void createHeaderBuffers(char *buffer, int info, int size)
{
// create the array containing the number of the packet and the data length
char temp[HEADER_LEN];
clearBuffer(temp, HEADER_LEN);
sprintf(temp, "%d", info);
int size_temp = strlen(temp);
int begin = size - size_temp;
for (int i = 0; i < size; i++)
{
if (i < begin) // fill the begining of the array with zero
{
buffer[i] = '0';
}
else // add the usefull info at the end e.g : 0000052
{
buffer[i] = temp[i - begin];
}
}
}
int createBuffer( char *buffer, char *data,int numPacket,int dataLength)
{
/* Create the buffer we will send*/
char numPacket_c[SIZE_PACKET+1];
char dataLength_c[5];
clearBuffer(buffer, BUFFERS_LEN);
clearBuffer(numPacket_c, 4);
clearBuffer(dataLength_c, 5);
createHeaderBuffers(numPacket_c, numPacket, SIZE_PACKET); // create the array containing the number of the packet
createHeaderBuffers(dataLength_c, dataLength, 4); // create the array containing the length of the data
for (int i = 0; i < BUFFERS_LEN; i++)
{
char ch;
if (i < SIZE_PACKET) // start by adding the number of the packet byte by byte
{
buffer[i] = numPacket_c[i];
}
else if (i < SIZE_PACKET+4) // then we add the length of the data
{
buffer[i] = dataLength_c[i- SIZE_PACKET];
}
else if (i < HEADER_LEN) // the the flag to say if it(s the end of the file
{
if(dataLength < DATA_LEN -1)
buffer[i] = '1';
else
buffer[i] = '0';
}
else if (i < HEADER_LEN + dataLength) // the the data
{
buffer[i] = data[i - HEADER_LEN];
}
else // fill the rest of the buffer with NULL character
{
buffer[i] = '\0';
}
}
return 0;
}
void copy(char *dest, char *source, int size)
{
/* Copy a buffer in another one byte by byte */
//printf("%s\n", source);
for (int i = 0; i < size; i++)
{
dest[i] = source[i];
//printf("%c\n", source[i]);
}
}
void readFile(char *buffer, int size, char *data, int *numPacket, int *dataLength, int *isEnd)
{
//print(buffer, size);
char isEnd_c[2];
char numPacket_c[SIZE_PACKET + 1];
char dataLength_c[5];
clearBuffer(isEnd_c, 2);
clearBuffer(numPacket_c, SIZE_PACKET + 1);
clearBuffer(dataLength_c, 5);
clearBuffer(data, DATA_LEN + 1);
for (int i = 0; i < size; i++)
{
if (i < SIZE_PACKET) // read the number of the packet
{
numPacket_c[i] = buffer[i];
printf("%c", buffer[i]);
}
else if (i < SIZE_PACKET + 4) // read the length of the data
{
dataLength_c[i - SIZE_PACKET] = buffer[i];
}
else if (i < HEADER_LEN) // read the isEnd FLAG
{
printf("\n%c\n", buffer[i]);
isEnd_c[0] = buffer[i];
}
else // read the data
{
data[i - HEADER_LEN] = buffer[i];
}
}
*numPacket = atoi(numPacket_c);
*isEnd = atoi(isEnd_c);
*dataLength = atoi(dataLength_c);
printf("%d ; %d ; %d\n", *numPacket, *dataLength, *isEnd);
}
unsigned short crc16(const unsigned char* numPacket, unsigned char length) {
unsigned char x;
unsigned short crc = 0xFFFF;
while (length--) {
x = crc >> 8 ^ *numPacket++;
x ^= x >> 4;
crc = (crc << 8) ^ ((unsigned short)(x << 12)) ^ ((unsigned short)(x << 5)) ^ ((unsigned short)x);
}
return crc;
}
//**********************************************************************
int main()
{
SOCKET socketS;
InitWinsock();
struct sockaddr_in local;
struct sockaddr_in from;
int fromlen = sizeof(from);
local.sin_family = AF_INET;
local.sin_port = htons(LOCAL_PORT);
local.sin_addr.s_addr = INADDR_ANY;
socketS = socket(AF_INET, SOCK_DGRAM, 0);
if (bind(socketS, (sockaddr*)&local, sizeof(local)) != 0) {
printf("Binding error!\n");
getchar(); //wait for press Enter
return 1;
}
//**********************************************************************
#ifdef SENDER
FILE *fp, *fp1;
char buffer_tx[BUFFERS_LEN];
int numPacket = 0;
char numberPacket[BUFFERS_LEN];
int isEnd = 0;
char test[100];
char header[HEADER_LEN];
char data[DATA_LEN];
char dataContent[DATA_LEN];
int len;
int num;
char *token;
sockaddr_in addrDest;
addrDest.sin_family = AF_INET;
addrDest.sin_port = htons(TARGET_PORT);
InetPton(AF_INET, _T(TARGET_IP), &addrDest.sin_addr.s_addr);
char *name = "test.jpg";
fp = fopen(name, "rb");
if (fp == NULL)
{
printf("error opening file\n");
}
fseek(fp, 0L, SEEK_END);
int sz = ftell(fp);
rewind(fp);
sz = (int)(sz / DATA_LEN) + 1;
strncpy(buffer_tx, name, BUFFERS_LEN); //put the nam of the file in the buffer
sendto(socketS, buffer_tx, BUFFERS_LEN, 0, (sockaddr*)&addrDest, sizeof(addrDest)); // send the name of the file
recvfrom(socketS, buffer_tx, BUFFERS_LEN, 0, (sockaddr*)&from, &fromlen); // wait aknowledgment
clearBuffer(buffer_tx, BUFFERS_LEN);
sprintf(buffer_tx, "%d", sz);
sendto(socketS, buffer_tx, BUFFERS_LEN, 0, (sockaddr*)&addrDest, sizeof(addrDest)); // send size of file
recvfrom(socketS, buffer_tx, BUFFERS_LEN, 0, (sockaddr*)&from, &fromlen); // wait aknowledgment
// This is to be sure that the receiver receive the name and the size correctly in the right order
clearBuffer(buffer_tx, BUFFERS_LEN);
clearBuffer(dataContent, DATA_LEN);
int n = 1;
int dataLength = 0;
while ((n = fread(dataContent, 1, DATA_LEN - 1,fp)) > 0) // read data of the file
{
clearBuffer(buffer_tx, BUFFERS_LEN); // clear the buffer for further utilisation
createBuffer(buffer_tx, dataContent, numPacket++, n); // add the header to the data |numPacket|dataLength|isEnd|data|
sendto(socketS, buffer_tx, BUFFERS_LEN, 0, (sockaddr*)&addrDest, sizeof(addrDest)); // send the packet
}
fclose(fp);
#endif // SENDER
#ifdef RECEIVER
FILE *fp;
char buffer_rx[BUFFERS_LEN];
Data *data;
int n = 0;
int k;
int how_many = 310;
//strncpy(buffer_rx, "12:1|salut", BUFFERS_LEN);
printf("Waiting for datagram ...\n");
int numPacket = 0;
int isEnd = 0;
int size = 0;
char size_file_c[BUFFERS_LEN];
int size_file = 0;
char header[HEADER_LEN];
char d[DATA_LEN + 1];
char name[BUFFERS_LEN];
char output[30];
char salut[DATA_LEN + 1];
sockaddr_in addrDest;
addrDest.sin_family = AF_INET;
addrDest.sin_port = htons(TARGET_PORT);
InetPton(AF_INET, _T(TARGET_IP), &addrDest.sin_addr.s_addr);
recvfrom(socketS, name, BUFFERS_LEN, 0, (sockaddr*)&from, &fromlen); // receiving name of file
sendto(socketS, name, BUFFERS_LEN, 0, (sockaddr*)&addrDest, sizeof(addrDest)); // send aknowledgment
recvfrom(socketS, size_file_c, BUFFERS_LEN, 0, (sockaddr*)&from, &fromlen); // receiving size of file
sendto(socketS, size_file_c, BUFFERS_LEN, 0, (sockaddr*)&addrDest, sizeof(addrDest)); // send aknowledgment
size_file = atoi(size_file_c);
// This is to be sure that the receiver receive the name and the size correctly in the right order
data = (Data *)calloc(size_file, sizeof(Data)); // allocate memory for the data
//closesocket(socketS);
//END;
//analyseBuffer(buffer_rx,d, &numPacket, &isEnd);
for (int i = 0; i < size_file; i++)
{
printf("waiting packet\n");
if ((k = recvfrom(socketS, buffer_rx, BUFFERS_LEN, 0, (sockaddr*)&from, &fromlen)) == SOCKET_ERROR) // receive a packet
{
printf("error during reception");
getchar();
return -1;
}
else
{
readFile(buffer_rx, BUFFERS_LEN, d, &numPacket, &size, &isEnd); // analyse the pacet to extract the data, the number of the packet, the data lenght and if it's the end
data[numPacket].data = (char*) calloc(size, 1); // allocate only the necessary memory
data[numPacket].size = size;
//print(d, DATA_LEN);
copy(data[numPacket].data, d, data[numPacket].size); // copy only the usefull info (without '\0')
printf("%d ; %d\n", i, size_file);
if (isEnd)
break;
clearBuffer(buffer_rx, BUFFERS_LEN); // clear the buffer for further utilisation
}
}
printf("file name : %s\n", name);
printf("enter the name of new file to be saved\n");
scanf("%s", output); // ask the user to set a file name
fp = fopen(output, "wb");
for (int i = 0; i <size_file; i++)
{
fwrite(data[i].data, data[i].size, 1, fp); // write the data to the file in the right order
}
fclose(fp); // close the file
closesocket(socketS);
#endif // RECEIVER
//**********************************************************************
getchar(); //wait for press Enter
return 0;
}
Notice the CRC-16 function , which is:
unsigned short crc16(const unsigned char* numPacket, unsigned char length) {
unsigned char x;
unsigned short crc = 0xFFFF;
while (length--) {
x = crc >> 8 ^ *numPacket++;
x ^= x >> 4;
crc = (crc << 8) ^ ((unsigned short)(x << 12)) ^ ((unsigned short)(x << 5)) ^ ((unsigned short)x);
}
return crc;
}
My question is : What is the best/easiest way to implement the CRC-16 function I have here? Do I pass a unsigned short crc parameter variable to the createBuffer() function, call the crc16() function inside the createBuffer() function and take the value it returns and assign it to the parameter value and then append it to the buffer?
Or is there a much simpler way to do it that I'm currently not thinking about?
Regarding What is the best/easiest way to implement the CRC-16 function I have here?
First, it appears your CRC-16 function is already implemented. How to use it is illustrated below.
CRC functions are typically used to take a file or buffer of any size as input, and produce a unique value for the purpose of verifying the contents of the file.
Here is a simple example of how I would use this function to read two types of input... (note, bufIn, and buf can be arrays of much larger sizes)
int main(void)
{
unsigned char bufIn[] = {1,45,76,23,245,9,54,55,210,90,23,54,78,14,27,86,34};
char buf[] = {"lkjahsloiwuyhfajsldnaouiyhrqkuhsldajnfdlakdsfa;jsidurfaliu;adjklflkja;sdlkjasdklfauiea;e"};
unsigned short crcOut1, crcOut2;
crcOut1 = crc16(bufIn, sizeof(bufIn)); //for bufIn returns 0x7782
crcOut2 = crc16(buf, sizeof(buf)); //for buf returns 0x98FB
return 0;
}
EDIT to address question in comment...
In your code, one possible way to use this is to call the crc16() function inside your fread while loop:
unsigned short packetCrc;
while ((n = fread(dataContent, 1, DATA_LEN - 1,fp)) > 0) // read data of the file
{
packetCrc = crc16(dataContent, n);
// verify packetCrc value against some expected value perhaps?
clearBuffer(buffer_tx, BUFFERS_LEN); // clear the buffer for further utilisation
createBuffer(buffer_tx, dataContent, numPacket++, n); // add the header to the data |numPacket|dataLength|isEnd|data|
sendto(socketS, buffer_tx, BUFFERS_LEN, 0, (sockaddr*)&addrDest, sizeof(addrDest)); // send the packet
}
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);
}
}
I was looking at basil00's torwall, and for fun was trying to pare it down to just intercept DNS. (provide an answer back to myself of 127.0.0.1 for webfiltering purposes, learning project)
however, at this point, I have it hijacking the dns packet, but it does not return a correct address. for every "blocked" domain, it's different.
for example, I put cbc.ca in my hosts.deny file (blacklist), and it returns an address of 0.4.114.2
then blacklisting slashdot, it will return 0.4.0.1
this has been quite confusing and frustrating, and after three days of research, I am out of ideas.
Here is the code to the redirect portion of my program, which seems to be where things go awry.
(note some of the comments will be goofy as I was hacking down a program for a different purpose and haven't cleaned it up yet)
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include "windivert.h"
#include "domain.h"
#include "main.h"
#include "redirect.h"
#define MAX_PACKET 4096
#define NUM_WORKERS 4
// DNS headers
#define DNS_MAX_NAME 254
struct dnshdr
{
uint16_t id;
uint16_t options;
uint16_t qdcount;
uint16_t ancount;
uint16_t nscount;
uint16_t arcount;
} __attribute__((__packed__));
struct dnsq
{
uint16_t type;
uint16_t class;
} __attribute__((__packed__));
struct dnsa
{
uint16_t name;
uint16_t type;
uint16_t class;
uint32_t ttl;
uint16_t length;
uint32_t addr;
} __attribute__((__packed__));
static DWORD redirect_worker(LPVOID arg);
static int handle_dns(HANDLE handle, PWINDIVERT_ADDRESS addr,
PWINDIVERT_IPHDR iphdr, PWINDIVERT_UDPHDR udphdr, char *data,
size_t data_len);
// State:
static bool redirect_on = false;
static HANDLE handle = INVALID_HANDLE_VALUE;
static HANDLE workers[NUM_WORKERS] = {NULL}; // Worker threads
// Send a packet asynchronously:
static void send_packet(HANDLE handle, void *packet, size_t packet_len,
PWINDIVERT_ADDRESS addr)
{
addr->Direction = WINDIVERT_DIRECTION_INBOUND;
WinDivertHelperCalcChecksums(packet, packet_len, 0);
if (!WinDivertSend(handle, packet, packet_len, addr, NULL))
debug("Send packet failed (err=%d)\n", (int)GetLastError());
}
// Start traffic redirect through Tor:
extern void redirect_start(void)
{
debug("DNS divert START\n");
if (handle != INVALID_HANDLE_VALUE)
return;
handle = WinDivertOpen(
"outbound and udp.DstPort == 53 or inbound and udp.DstPort = 53", 0, 0, 0);
// Launch threads:
redirect_on = true;
for (size_t i = 0; i < NUM_WORKERS; i++)
{
workers[i] = CreateThread(NULL, MAX_PACKET*3,
(LPTHREAD_START_ROUTINE)redirect_worker, (LPVOID)handle, 0, NULL);
if (workers[i] == NULL)
{
exit(EXIT_FAILURE);
}
}
}
// Stop traffic redirect through Tor:
extern void redirect_stop(void)
{
debug("DNS divert STOP\n");
if (handle == INVALID_HANDLE_VALUE)
return;
// Close the WinDivert handle; will cause the workers to exit.
redirect_on = false;
if (!WinDivertClose(handle))
{
exit(EXIT_FAILURE);
}
handle = INVALID_HANDLE_VALUE;
for (size_t i = 0; i < NUM_WORKERS; i++)
{
WaitForSingleObject(workers[i], INFINITE);
workers[i] = NULL;
}
}
// Redirect worker thread:
static DWORD redirect_worker(LPVOID arg)
{
HANDLE handle = (HANDLE)arg;
// Packet processing loop:
char packet[MAX_PACKET];
UINT packet_len;
WINDIVERT_ADDRESS addr;
while (redirect_on)
{
if (!WinDivertRecv(handle, packet, sizeof(packet), &addr, &packet_len))
{
// Silently ignore any error.
continue;
}
PWINDIVERT_IPHDR iphdr = NULL;
PWINDIVERT_TCPHDR tcphdr = NULL;
PWINDIVERT_UDPHDR udphdr = NULL;
PVOID data = NULL;
UINT data_len;
WinDivertHelperParsePacket(packet, packet_len, &iphdr, NULL, NULL,
NULL, &tcphdr, &udphdr, &data, &data_len);
int dnshandle = 0;
if (udphdr != NULL && ntohs(udphdr->DstPort) == 53)
dnshandle = handle_dns(handle, &addr, iphdr, udphdr, data, data_len);
if(dnshandle != 1)
{
if (!WinDivertSend(handle, packet, packet_len, &addr, NULL))
{
}
}
}
return 0;
}
// Handle DNS requests.
// NOTES:
// - If anything goes wrong, we simply drop the packet without error.
// - An alternative approach would be to let Tor resolve the address, however,
// this would be slow.
static int handle_dns(HANDLE handle, PWINDIVERT_ADDRESS addr,
PWINDIVERT_IPHDR iphdr, PWINDIVERT_UDPHDR udphdr, char *data,
size_t data_len)
{
struct dnshdr *dnshdr = (struct dnshdr *)data;
data += sizeof(struct dnshdr);
data_len -= sizeof(struct dnshdr);
char name[DNS_MAX_NAME + 8]; // 8 bytes extra.
size_t i = 0;
while (i < data_len && data[i] != 0)
{
size_t len = data[i];
if (i + len >= DNS_MAX_NAME)
return -1;
name[i++] = '.';
for (size_t j = 0; j < len; j++, i++)
name[i] = data[i];
}
name[i++] = '\0';
// Generate a fake IP address and associate it with this domain name:
uint32_t fake_addr = domain_lookup_addr(name);
if (fake_addr == 0)
{
// This domain is blocked; so ignore the request.
// Construct a query response:
size_t len = sizeof(struct dnshdr) + data_len + sizeof(struct dnsa);
if (len > 512) // Max DNS packet size.
return -1;
len += sizeof(WINDIVERT_IPHDR) + sizeof(WINDIVERT_UDPHDR) + len;
char buf[len + 8]; // 8 bytes extra.
PWINDIVERT_IPHDR riphdr = (PWINDIVERT_IPHDR)buf;
PWINDIVERT_UDPHDR rudphdr = (PWINDIVERT_UDPHDR)(riphdr + 1);
struct dnshdr *rdnshdr = (struct dnshdr *)(rudphdr + 1);
char *rdata = (char *)(rdnshdr + 1);
UINT local_ip;
DivertHelperParseIPv4Address("127.0.0.1",&local_ip);
memset(riphdr, 0, sizeof(WINDIVERT_IPHDR));
riphdr->Version = 4;
riphdr->HdrLength = sizeof(WINDIVERT_IPHDR) / sizeof(uint32_t);
riphdr->Length = htons(len);
riphdr->Id = htons(0xF00D);
WINDIVERT_IPHDR_SET_DF(riphdr, 1);
riphdr->TTL = 64;
riphdr->Protocol = IPPROTO_UDP;
riphdr->SrcAddr = iphdr->DstAddr;
riphdr->DstAddr = iphdr->SrcAddr;
memset(rudphdr, 0, sizeof(WINDIVERT_UDPHDR));
rudphdr->SrcPort = htons(53); // DNS
rudphdr->DstPort = udphdr->SrcPort;
rudphdr->Length = htons(len - sizeof(WINDIVERT_IPHDR));
rdnshdr->id = dnshdr->id;
rdnshdr->options = htons(0x8180); // Standard DNS response.
rdnshdr->qdcount = htons(0x0001);
rdnshdr->ancount = htons(0x0001);
rdnshdr->nscount = 0;
rdnshdr->arcount = 0;
memcpy(rdata, data, data_len);
struct dnsa *rdnsa = (struct dnsa *)(rdata + data_len);
rdnsa->name = htons(0xC00C);
rdnsa->type = htons(0x0001); // (A)
rdnsa->class = htons(0x0001); // (IN)
rdnsa->ttl = htonl(0x00000258) ; // 1 second
rdnsa->length = htons(0x0004);
rdnsa->addr = htonl(local_ip); // Fake address
send_packet(handle, &buf, len, addr);
debug("address: %u\n",addr->Direction);
debug("Intercept DNS %s\n", (name[0] == '.'? name+1: name));
return 1;
}
// Re-inject the matching packet.
/*
/
*/
return 0;
}
Here's the domain lookup side of it (mostly just hacked down to try to get the results I want:
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <windows.h>
#include "domain.h"
#include "main.h"
#define RATE_LIMIT 8000
#define rand16() \
(rand() & 0xFF) | ((rand() & 0xFF) << 8)
// Domain blacklist:
struct blacklist
{
size_t size;
size_t len;
char **names;
};
static struct blacklist *blacklist = NULL;
// State:
static struct name *names[UINT16_MAX] = {NULL};
static HANDLE names_lock = NULL;
// Prototypes:
static struct blacklist *domain_blacklist_read(const char *filename);
static bool domain_blacklist_lookup(struct blacklist *blacklist,
const char *name);
static int __cdecl domain_blacklist_compare_0(const void *x, const void *y);
static int domain_blacklist_compare(const char *name0, size_t len,
const char *name1);
// Initialize this module:
extern void domain_init(void)
{
// Load the domain blacklist.
blacklist = domain_blacklist_read("hosts.deny");
}
// Lookup an address given a domain name. If the name does not exist then
// create one.
extern uint32_t domain_lookup_addr(const char *name0)
{
if (name0[0] == '.')
name0++;
if (domain_blacklist_lookup(blacklist, name0))
{
debug("Block %s\n", name0);
return 0; // Blocked!
}
return;
}
// Read the blacklist file:
static struct blacklist *domain_blacklist_read(const char *filename)
{
struct blacklist *blacklist =
(struct blacklist *)malloc(sizeof(struct blacklist));
if (blacklist == NULL)
{
exit(EXIT_FAILURE);
}
blacklist->size = 0;
blacklist->len = 0;
blacklist->names = NULL;
FILE *stream = fopen(filename, "r");
if (stream == NULL)
{
return blacklist;
}
// Read blocked domains:
int c;
char buf[256];
while (true)
{
while (isspace(c = getc(stream)))
;
if (c == EOF)
break;
if (c == '#')
{
while ((c = getc(stream)) != '\n' && c != EOF)
;
continue;
}
size_t i = 0;
while (i < sizeof(buf)-1 && (c == '-' || c == '.' || isalnum(c)))
{
buf[i++] = c;
c = getc(stream);
}
if (i >= sizeof(buf)-1 || !isspace(c))
{
exit(EXIT_FAILURE);
}
buf[i] = '\0';
if (blacklist->len >= blacklist->size)
{
blacklist->size = (blacklist->size == 0? 32: 2 * blacklist->size);
blacklist->names = (char **)realloc(blacklist->names,
blacklist->size * sizeof(char *));
if (blacklist->names == NULL)
{
exit(EXIT_FAILURE);
}
}
size_t size = (i+1) * sizeof(char);
char *name = (char *)malloc(size);
if (name == NULL)
{
exit(EXIT_FAILURE);
}
for (size_t j = 0; j < i; j++)
name[j] = buf[i - 1 - j];
name[i] = '\0';
blacklist->names[blacklist->len++] = name;
}
fclose(stream);
qsort(blacklist->names, blacklist->len, sizeof(char *),
domain_blacklist_compare_0);
return blacklist;
}
// Check if a domain matches the blacklist or not:
static bool domain_blacklist_lookup(struct blacklist *blacklist,
const char *name)
{
if (blacklist->len == 0)
return false;
size_t len = strlen(name);
ssize_t lo = 0, hi = blacklist->len-1;
while (lo <= hi)
{
ssize_t mid = (lo + hi) / 2;
int cmp = domain_blacklist_compare(name, len, blacklist->names[mid]);
if (cmp > 0)
hi = mid-1;
else if (cmp < 0)
lo = mid+1;
else
return true;
}
return false;
}
// Domain compare function(s):
static int __cdecl domain_blacklist_compare_0(const void *x, const void *y)
{
const char *name0 = *(const char **)x;
const char *name1 = *(const char **)y;
return strcmp(name0, name1);
}
static int domain_blacklist_compare(const char *name0, size_t len,
const char *name1)
{
size_t i = 0;
ssize_t j = (ssize_t)len - 1;
for (; j >= 0 && name1[i] != '\0'; i++, j--)
{
int cmp = (int)name1[i] - (int)name0[j];
if (cmp != 0)
return cmp;
}
if (j < 0 && name1[i] != '\0')
return 1;
return 0;
}
any assistance is appreciated.
Also, I have uploaded the code to: Github
Thank you.
There's one of two things going on here. You're reading and writing DNS packets incorrectly, and or you're failing to convert the addresses to or from host to network order before working with them.
I'm going to bet on you reading and writing DNS packets incorrectly. I've implemented my own filtering systems using WinDivert where I was hijacking and passing all DNS traffic through my own local DNS server and I've seen these fudged addresses come out exactly as the results you're getting when I was parsing and writing DNS packets incorrectly.
The bad news is, I can't point you to a full DNS library in C/C++ as I know of none that actually make the job easier (maybe, see edits). I personally had my diversion code written in C++ with WinDivert and then use Arsoft.Tools.Net C# DNS library for actually running a local DNS server and manipulating DNS responses.
There is one project in C++ that calls itself boost::net::dns because I think the writer was hoping it would be part of boost, which it isn't and probably won't be. Avoid this library as the internal mechanism for parsing and storing multiple A Records is bugged out and broken and you'll get the same wacky results you're getting here. I tried to work with him to get it fixed but, he was only interested in blaming my code.
I'll have a gander again and update my answer if I can find a decent lib for working with DNS packets in C++. Don't try to do it yourself, we're talking about entire protocols with entire books of RFC's to do this properly yourself.
Update
As promised, here are some results from my search:
Mozilla Necko (Formerly Netlib)
http://mxr.mozilla.org/mozilla-central/source/netwerk/dns/
C-Ares:
https://github.com/bagder/c-ares
A list of alternative libraries C-Ares compiled:
http://c-ares.haxx.se/otherlibs.html
Also, it is linux specific but pretty clean code. You might be able to pilfer through libcrafter's DNS classes and move them to your own project.
https://github.com/pellegre/libcrafter/blob/master/libcrafter/crafter/Protocols/DNS.h
Again, unless your "learning project" is understanding and recreating one of the foundational pillars of the internet, don't implement this yourself. Try and use one of the previously listed libraries to handle your DNS packets.