So I'm doing the CS50 pset4 recover task (where you need to search for jpg files on a memory card and whenever you find one- you open a new file and write the jpg found to the new file). I have written the code in a slightly different manner then what is told in the course but I think(hope) my logic is right. I am able to recover all 50 images but the images are incomplete and distorted. Also for some reason the 050th image is not opening. Here is my code
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
typedef uint8_t BYTE; //defining a byte = 8 bits or 8 0's or 1's
int main(int argc, char *argv[]) {
//assigning variables
int BLOCK_SIZE = 512;
BYTE buffer[BLOCK_SIZE];
int i = 0;
char* nf = malloc(sizeof(int)*3);
//checking to see a file name is given
if (argc != 2)
{
printf("Usage: ./recover IMAGE\n");
return 1;
}
//opening said file
FILE *rfile = fopen(argv[1], "r");
if(rfile == NULL)
{
printf("File '%s' does not exist\n", argv[1]);
return 1;
}
//opening a copy
FILE *c = fopen(argv[1], "r");
if(c == NULL)
{
printf("File '%s' does not exist\n", argv[1]);
return 1;
}
//checking 512 bytes again and again for orginal
while (fread (buffer, 1, BLOCK_SIZE, rfile) == BLOCK_SIZE)
{
fseek(c, ftell(rfile) , SEEK_SET); //fread (buffer, 1, BLOCK_SIZE, c);
sprintf(nf, "%03i.jpg", i); //000, 001, 002
//opening a file to write in
FILE *img = fopen(nf, "w");
if(img == NULL)
{
return 1;
}
//Is it a jpeg!?
if (buffer[0]==0xff && buffer[1]==0xd8 && buffer[2]==0xff && (buffer[3] & 0xf0) == 0xe0)
{
//writing the img in a file called img
fwrite(buffer, 512, 1, img);
fwrite(c, BLOCK_SIZE, 2048, img);
i++; //making sure a new file is opened next time
}
fclose(img);
}
fclose(c);
fclose(rfile);
free(nf); }
Related
I am getting a 'Segmentation fault (core dumped) error'
I know that means I am accessing memory I shouldn't.
The error is coming in the outer else loop with the fwrite function. fwrite(buffer, 1, 512, img);
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
int main(int argc, char *argv[])
{
if (argc != 2)
{
printf("Usage: ./recover IMAGE\n");
return 1;
}
FILE *file = fopen(argv[1], "r");
if (file == NULL)
{
printf("File entered does not exist\n");
return 1;
}
typedef uint8_t BYTE;
BYTE buffer[512];
char filename[8];
int i = 0;
FILE *img;
while (fread(buffer, 1, 512, file) == 512)
{
// check if first three bytes are 0xff 0xd8 0xff
// check if 4th byte is 0xe0, 0xe1, 0xe2, ..., 0xef
// if those 4 bytes are found then start writing these bytes to a file ###.jpg
// once you see the 4 bytes again, stop writing to the current file and make a new file ###.jpg to write to
if (buffer[0] == 0xff && buffer[1] == 0xd8 && buffer[2] == 0xff && (buffer[3] & 0xf0) == 0xe0)
{
if (i == 0)
{
sprintf(filename, "%03i.jpg", i);
img = fopen(filename, "w");
i += 1;
}
else
{
fclose(img);
sprintf(filename, "%03i.jpg", i);
img = fopen(filename, "w");
i += 1;
}
fwrite(buffer, 1, 512, img);
}
else
{
fwrite(buffer, 1, 512, img);
}
}
fclose(img);
return 0;
}
Any ideas, hints or tips would be appreciated.
This is my first time posting in stackoverflow :D
Solved:
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
int main(int argc, char *argv[])
{
if (argc != 2)
{
printf("Usage: ./recover IMAGE\n");
return 1;
}
FILE *file = fopen(argv[1], "r");
if (file == NULL)
{
printf("File entered does not exist\n");
return 1;
}
typedef uint8_t BYTE;
BYTE buffer[512];
char filename[8];
int i = 0;
FILE *img;
while (fread(buffer, 1, 512, file) == 512)
{
// check if first three bytes are 0xff 0xd8 0xff
// check if 4th byte is 0xe0, 0xe1, 0xe2, ..., 0xef
// if those 4 bytes are found then start writing these bytes to a file ###.jpg
// once you see the 4 bytes again, stop writing to the current file and make a new file ###.jpg to write to
if (buffer[0] == 0xff && buffer[1] == 0xd8 && buffer[2] == 0xff && (buffer[3] & 0xf0) == 0xe0)
{
if (i == 0)
{
sprintf(filename, "%03i.jpg", i);
img = fopen(filename, "w");
i += 1;
}
else
{
fclose(img);
sprintf(filename, "%03i.jpg", i);
img = fopen(filename, "w");
i += 1;
}
fwrite(buffer, 1, 512, img);
}
else
{
if (i > 0)
{
fwrite(buffer, 512, 1, img);
}
}
}
fclose(img);
return 0;
}
I need to recover jpeg files from a memory card (raw data). I have done the code below but I am getting a seg fault which i cannot identify the source. Just to summarize, I´ve done a loop to read 512bytes chunks and look for specific jpeg header. If it is the first jpeg, the programa will open a file and keep writing to it. If jpeg is not the first, close previous image and keep writing to it.
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
int main(int argc, char *argv[])
{
// Check usage
if (argc != 2)
{
printf("Usage: ./recover image\n");
return 1;
}
// Open file
FILE *file = fopen(argv[1], "r");
if (!file)
{
fprintf(stderr, "Could not open %s.\n", argv[1]);
return 1;
}
// open array to store the chunks with enough memory
unsigned char buffer [512];
// variables jpeg count
int img_count = 0;
// open filename img to write to
char filename[8];
FILE *img = NULL;
// create loop to read 512 chunks
while (fread(buffer, 512, 1, file) > 0)
{
if (buffer[0] == 0xff && buffer[1] == 0xd8 && buffer[2] == 0xff && (buffer[3] & 0xf0) == 0xe0)
{
// if theres already a jpeg open
if (img_count > 0)
{
fclose(img);
sprintf(filename, "%i03.jpg", img_count);
img = fopen(filename, "w");
img_count++;
} // first jpeg img count == 0
else if (img_count == 0)
{
sprintf(filename, "%i03.jpg", img_count);
img = fopen(filename, "w");
img_count++;
}
}
//if this is not a new jpeg header, just write to img
if (img_count > 0)
{
fwrite(buffer, 512, 1, img);
}
else
{
continue;
}
}
fclose(img);
fclose(file);
return 0;
}
Found it...typo i had "%i03.jpg" instead of %03i.jpg"
The question essentially is how to correctly apply gain to an audio sample?
I'm programming on FreeBSD and OSS, but manipulate volume in audio sample is probably the same for other OS and applications.
I'm studying others' applications internals like ecasound (in C++) and SoX (in C) but I don't know whats wrong when I read a sample and apply gain to it : it becomes distorted and noisy. My point is to understand why it is not working to turn the volume down (gain lesser than 1).
I'm working with stereo 16 bit LE samples. Without applying gain, it works perfectly (recording and playback).
I thought that I should convert an integer sample to float; multiply by a gain factor and restore it to integer. But it is not working. And it seems to be the exact same approach for SoX in src/vol.c in function static int flow.
Below is my code (no additional libs used). The function playback is where I'm applying gain.
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include "/usr/include/sys/soundcard.h"
#include <sys/ioctl.h>
#include <sys/time.h>
#include <sys/stat.h> //man 2 chmod
#include <signal.h>
#define DEBUG 1
#define log(msg) if (DEBUG) printf("[LOG] %s\n",msg)
#define err(msg) {printf("[ERR] %s\n",msg); exit(1); }
const char *device = "/dev/dsp3.1"; //Audio device
char *rawFile = "/tmp/raw-file.wav"; //Raw file to record and playback
int fragmentSize = 256;
int b_continue = 1;
void signalHandler(int sigNum){
log("Signal captured");
b_continue = 0;
}
void configDevice(int fdDsp){
int ossCapabilities = 0;
if(fdDsp == -1)
err("can't open device");
if( ioctl(fdDsp, SNDCTL_DSP_GETCAPS, &ossCapabilities) == -1)
err("unsupported: SNDCTL_DSP_GETCAPS");
/*
* http://www.opensound.com/pguide/audio2.html
*/
if(ossCapabilities & DSP_CAP_TRIGGER != DSP_CAP_TRIGGER){
err("Triggering of recording/playback is not possible with this OSS device.");
}
if(ossCapabilities & DSP_CAP_REALTIME != DSP_CAP_REALTIME){
err("No DSP_CAP_REALTIME.");
}
if(ioctl(fdDsp, SNDCTL_DSP_SETDUPLEX, &ossCapabilities) == -1)
err("can't SNDCTL_DSP_SETDUPLEX");
if(ossCapabilities & DSP_CAP_DUPLEX != DSP_CAP_DUPLEX)
err("can't DSP_CAP_DUPLEX");
int format = AFMT_S16_LE; //set format
if(ioctl(fdDsp, SNDCTL_DSP_SETFMT, &format ) == -1){
err("Error setting format.");
}
int channels = 1; //mono=0 stereo=1
if(ioctl(fdDsp, SNDCTL_DSP_STEREO, &channels ) == -1){
err("Error setting channels." );
}
// FREQUENCY RATE
int speed = 44100;
if(ioctl(fdDsp, SNDCTL_DSP_SPEED, &speed ) == -1){
err("Error setting speed.");
}
// FRAGMENT SIZE
if(ioctl(fdDsp, SNDCTL_DSP_SETBLKSIZE, &fragmentSize) == -1){ //normalmente 2048 bits
err("Cannot SNDCTL_DSP_SETBLKSIZE.");
}
}
void record(){
int fdDsp = open(device, O_RDONLY);
configDevice(fdDsp);
//create file for writing
const int fdOutput = open(rawFile, O_WRONLY | O_CREAT, S_IWUSR | S_IRUSR);
if(fdOutput ==-1)
err("can't open file to write");
log("Recording...");
do{
// Triggers recording
int enableBits = PCM_ENABLE_INPUT;
if(ioctl(fdDsp, SNDCTL_DSP_SETTRIGGER, &enableBits) == -1)
err("Can't record: SNDCTL_DSP_SETTRIGGER");
int *buf[fragmentSize];
read(fdDsp, buf, fragmentSize);
write(fdOutput, buf, fragmentSize);
} while(b_continue == 1);
close(fdOutput);
close(fdDsp);
}
void playback(){
log("Opening file:");
log(rawFile);
log("On device:");
log(device);
int fdDsp = open(device, O_WRONLY);
configDevice(fdDsp);
const int fdInput = open(rawFile, O_RDONLY);
if(fdInput ==-1)
err("can't open file");
log("Playing...");
int eof = 0;
do{
// TRIGGERs PLAYBACK
int enableBits = PCM_ENABLE_OUTPUT;
if(ioctl(fdDsp, SNDCTL_DSP_SETTRIGGER, &enableBits) == -1){
err("Cannot SNDCTL_DSP_SETTRIGGER.");
}
int buf[fragmentSize];
eof = read(fdInput, buf, fragmentSize); //bytes read or -1 if EOF
// audio processing:
for(int i=0;i<fragmentSize;i++){
// learning how to get left and right channels from buffer
int l = (buf)[i] & 0xffff;
int r = ((buf)[i] >> 16) & 0xffff ;
// FIXME: it is causing distortion:
float fl = l;
float fr = r;
fl *= 1.0;
fr *= 0.3; //if different than 1, sounds distorted and noisy
l = fl;
r = fr;
// OK: unite Left and Right channels again
int lr = (l ) | (r << 16);
// OK: other options to mix these two channels:
int lleft = l; //Just the left channel
int rright = (r << 16); //Just the right channel
int lmono = (l << 16) | l; //Left ch. on both channels
int rmono = (r << 16) | r; //Right ch. on both channels
// the output:
(buf)[i] = lr;
}
write(fdDsp, buf, fragmentSize);
if(b_continue == 0) break;
} while(eof > 0);
close(fdInput);
close(fdDsp);
}
int main(int argc, char *argv[])
{
signal(SIGINT, signalHandler);
log("Ctrl^C to stop recording/playback");
record();
b_continue = 1; playback();
log("Stopped.");
return 0;
}
UPDATE:
As pointed out by CL, I was using the wrong type and the last parameter of read()/write() is greater than the size of the buffer.
So, in FreeBSD I changed the buffer type to int16_t (short) defined in #include <stdint.h> .
Now I can correctly apply a gain as desired:
float fl = l;
float fr = r;
fl *= 1.0f;
fr *= 1.5f;
l = fl;
r = fr;
I'll accept CL's answer.
Now the audio processing loop is working with one sample per time (left and right interleaved).
Updated code:
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include "/usr/include/sys/soundcard.h"
#include <sys/ioctl.h>
#include <sys/time.h>
#include <sys/stat.h> //man 2 chmod
#include <signal.h>
#include <stdint.h> //has type int16_t (short)
#define DEBUG 1
#define log(msg) if (DEBUG) printf("[LOG] %s\n",msg)
#define err(msg) {printf("[ERR] %s\n",msg); exit(1); }
const char *device = "/dev/dsp3.1"; //Audio device
char *rawFile = "/tmp/stereo.wav"; //Raw file to record and playback
int fragmentSize = 256;
int b_continue = 1;
void signalHandler(int sigNum){
log("Signal captured");
b_continue = 0;
}
void configDevice(int fdDsp){
int ossCapabilities = 0;
if(fdDsp == -1)
err("can't open device");
if( ioctl(fdDsp, SNDCTL_DSP_GETCAPS, &ossCapabilities) == -1)
err("unsupported: SNDCTL_DSP_GETCAPS");
/*
* http://www.opensound.com/pguide/audio2.html
*/
if(ossCapabilities & DSP_CAP_TRIGGER != DSP_CAP_TRIGGER){
err("Triggering of recording/playback is not possible with this OSS device.");
}
if(ossCapabilities & DSP_CAP_REALTIME != DSP_CAP_REALTIME){
err("No DSP_CAP_REALTIME.");
}
if(ioctl(fdDsp, SNDCTL_DSP_SETDUPLEX, &ossCapabilities) == -1)
err("can't SNDCTL_DSP_SETDUPLEX");
if(ossCapabilities & DSP_CAP_DUPLEX != DSP_CAP_DUPLEX)
err("can't DSP_CAP_DUPLEX");
int format = AFMT_S16_LE; //set format
if(ioctl(fdDsp, SNDCTL_DSP_SETFMT, &format ) == -1){
err("Error setting format.");
}
int channels = 1; //mono=0 stereo=1
if(ioctl(fdDsp, SNDCTL_DSP_STEREO, &channels ) == -1){
err("Error setting channels." );
}
// FREQUENCY RATE
int speed = 44100;
if(ioctl(fdDsp, SNDCTL_DSP_SPEED, &speed ) == -1){
err("Error setting speed.");
}
// FRAGMENT SIZE
if(ioctl(fdDsp, SNDCTL_DSP_SETBLKSIZE, &fragmentSize) == -1){ //normalmente 2048 bits
err("Cannot SNDCTL_DSP_SETBLKSIZE.");
}
}
void record(){
int fdDsp = open(device, O_RDONLY);
configDevice(fdDsp);
//create file for writing
const int fdOutput = open(rawFile, O_WRONLY | O_CREAT, S_IWUSR | S_IRUSR);
if(fdOutput ==-1)
err("can't open file to write");
log("Recording...");
do{
// Triggers recording
int enableBits = PCM_ENABLE_INPUT;
if(ioctl(fdDsp, SNDCTL_DSP_SETTRIGGER, &enableBits) == -1)
err("Can't record: SNDCTL_DSP_SETTRIGGER");
// Wrong:
// int *buf[fragmentSize];
// read(fdDsp, buf, fragmentSize);
// write(fdOutput, buf, fragmentSize);
int16_t *buf[fragmentSize/sizeof (int16_t)];
read(fdDsp, buf, fragmentSize/sizeof (int16_t));
write(fdOutput, buf, fragmentSize/sizeof (int16_t));
} while(b_continue == 1);
close(fdOutput);
close(fdDsp);
}
void playback(){
log("Opening file:");
log(rawFile);
log("On device:");
log(device);
int fdDsp = open(device, O_WRONLY);
configDevice(fdDsp);
const int fdInput = open(rawFile, O_RDONLY);
if(fdInput ==-1)
err("can't open file");
log("Playing...");
int eof = 0;
do{
// TRIGGERs PLAYBACK
int enableBits = PCM_ENABLE_OUTPUT;
if(ioctl(fdDsp, SNDCTL_DSP_SETTRIGGER, &enableBits) == -1){
err("Cannot SNDCTL_DSP_SETTRIGGER.");
}
//Wrong buffer type (too large) and wrong last parameter for read():
// int buf[fragmentSize];
// eof = read(fdInput, buf, fragmentSize);
int16_t buf[fragmentSize/sizeof (int16_t)];
eof = read(fdInput, buf, fragmentSize/sizeof (int16_t));
// audio processing:
for(int i=0;i<fragmentSize/sizeof (int16_t);i++){
int16_t l = buf[i];
int16_t r = buf[i+1];
// Using int16_t (short) buffer, gain works but stereo is inverted with factor >= 1.4f
float fl = l;
float fr = r;
fl *= 2.0f;
fr *= 3.0f;
l = fl;
r = fr;
// the output:
(buf)[i] = l;
i++;
(buf)[i] = r;
}
// write(fdDsp, buf, fragmentSize); //wrong
write(fdDsp, buf, fragmentSize/sizeof (int16_t));
if(b_continue == 0) break;
} while(eof > 0);
close(fdInput);
close(fdDsp);
}
int main(int argc, char *argv[])
{
signal(SIGINT, signalHandler);
log("Ctrl^C to stop recording/playback");
record();
b_continue = 1; playback();
log("Stopped.");
return 0;
}
Thanks,
The last parameter of read()/write() is the number of bytes, but an entry in buf[] has more than one byte.
In the two's complement representation of binary numbers, negative values are (or must be) sign extended, i.e., the most significant bits are ones. In this code, neither extracting L/R channels nor combining them works correctly for negative samples.
The easiest way of handling negative samples would be to use one array entry per sample, i.e., short int.
So I am currently attempting recover.c from the cs50 pset3 and I have recovered all 49 jpeg files. However, all these jpeg files are empty (with a grey and white grid). Could someone please explain where my code went wrong? I tried check50 to see if my code was correct but it said the recovered images do not match.
I changed my "w" to "wb" in my fopen function too but that didn't seem to work either.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <stdbool.h>
int main(int argc, char *argv[])
{
//a data type that can store a byte
typedef uint8_t BYTE;
//Checking to see if there is only one command line argument
if (argc != 2)
{
fprintf(stderr, "Usage: ./recover image\n" );
return 1;
}
//Opening the file to see if its correct
char *infile = argv[1];
FILE *memory = fopen(infile, "r");
if (memory == NULL)
{
fprintf(stderr, "Could not open %s.\n", infile);
return 2;
}
//Creation of a buffer
BYTE buffer[512] = {0};
//Whether or not we have found a JPEG or not
bool jpegfound = false;
//the number of JPEG files found
int numJPEGfile = 0;
//declaring the new to be JPEG file so that it has a scope for the
whole while loop
FILE *img = NULL;
//declaring the new JPEG filename
char filename[8];
//Repeating until the end of card
while(fread(buffer, 512, 1, memory) == 1)
{
//Start of a new JPEG?
if (buffer[0] == 0xff && buffer[1] == 0xd8 && buffer[2] == 0xff && (buffer[3] & 0xf0) == 0xe0)
{
jpegfound = true;
sprintf(filename, "%03i.jpg", numJPEGfile);
numJPEGfile += 1;
img = fopen(filename, "wb");
fwrite(buffer, 512, 1, img);
}
//Have we already found a JPEG?
if(jpegfound)
{
jpegfound = false;
fclose(img);
}
}
//Close any remaining files
fclose(memory);
return 0;
}
If you run the below command in the terminal, how large are the jpg-files you recovered? I think this will give you a hint for solving this pset.
ls -l
My question is regarding the Recover assignment as part of CS50.
The code is running (finally) and it produces 50 JPEG files, and most of them are the correct images, except the first file is not an image, therefore it doesn't pass check50.
I have spent a long time trying to figure out what the problem is but I cannot pinpoint it so I am hoping someone might be able to help me out so I can move on.
Thanks in advance! Here is my code:
int main(int argc, char *argv[])
{
// ensure proper usage
if (argc != 2)
{
fprintf(stderr, "Usage: Name of Memory Card File\n");
return 1;
}
char *readfile = argv[1];
// open memory card file
FILE *card_ptr = fopen(readfile, "r");
if (card_ptr == NULL)
{
fprintf(stderr, "Could not open %s.\n", readfile);
return 2;
}
//Declare a buffer to read into
unsigned char *buffer = malloc(512);
//to check if we have already found a file
bool (jpgAlreadyNew) = false;
//declare counter for the number of files found and a file pointer
int filenumber = 0;
FILE *new_jpg_ptr = NULL;
char filename[8];
//read in bytes until reach EOF
while (fread(buffer, 1, 512, card_ptr) != 0x00)
{
//if we reach the header pattern of bytes
if (buffer [0] == 0xff && buffer [1] == 0xd8 && buffer [2] == 0xff && (buffer [3] & 0xf0) == 0xe0)
{
//if there is not already a JPEG file found
if (!jpgAlreadyNew)
{
//change the bool value
(jpgAlreadyNew) = true;
//open new file
sprintf(filename, "%03i.jpg", filenumber);
new_jpg_ptr = fopen(filename, "w");
if (new_jpg_ptr == NULL)
{
return 3;
}
//add to counter of files found
filenumber++;
//write files from buffer into new img file
fwrite(buffer, 1, 512, new_jpg_ptr);
}
//if there is already a JPEG file found
if (jpgAlreadyNew)
{
//close the previous file which would now be complete
fclose(new_jpg_ptr);
//open new file
sprintf(filename, "%03i.jpg", filenumber);
new_jpg_ptr = fopen(filename, "w");
if (new_jpg_ptr == NULL)
{
return 4;
}
//add to counter of files found
filenumber++;
//write files from buffer into new img file
fwrite(buffer, 1, 512, new_jpg_ptr);
}
}
// else if we do not see pattern of header bytes
else
{
//if already found a jpg file which is open then write the bytes to that file
if (jpgAlreadyNew)
{
fwrite(buffer, 1, 512, new_jpg_ptr);
}
//if no file found yet, discard and move on
if (!jpgAlreadyNew)
{
continue;
}
}
}
//free memory
free (buffer);
//close pointers and end program successfully
fclose(card_ptr);
fclose(new_jpg_ptr);
return 0;
}
Let's walk through the program starting with finding the first jpeg signature:
This if (!jpgAlreadyNew) evaluates to true, so it enters the if block; the first thing it does is (jpgAlreadyNew) = true;. When it is done creating the file and writing the first block, what happens next? This if (jpgAlreadyNew). Which also evaluates to true. So it closes 000.jpg and moves along.
Since jpgAlreadyNew is a boolean, an if {} else {} construct would suffice.