I need to write RTSP steram from IP-cam to file. I use FFMPEG to do this. I found code example on C++, but i need to use only C. Can anyone help me?
i have problems in file operations. how can i write stream to file?
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <fstream>
#include <sstream>
extern "C" {
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libavformat/avio.h>
#include <libswscale/swscale.h>
}
int main(int argc, char** argv) {
// Open the initial context variables that are needed
SwsContext *img_convert_ctx;
AVFormatContext* format_ctx = avformat_alloc_context();
AVCodecContext* codec_ctx = NULL;
int video_stream_index;
// Register everything
av_register_all();
avformat_network_init();
//open RTSP
if (avformat_open_input(&format_ctx, "rtsp://134.169.178.187:8554/h264.3gp",
NULL, NULL) != 0) {
return EXIT_FAILURE;
}
if (avformat_find_stream_info(format_ctx, NULL) < 0) {
return EXIT_FAILURE;
}
//search video stream
for (int i = 0; i < format_ctx->nb_streams; i++) {
if (format_ctx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO)
video_stream_index = i;
}
AVPacket packet;
av_init_packet(&packet);
//open output file
AVFormatContext* output_ctx = avformat_alloc_context();
AVStream* stream = NULL;
int cnt = 0;
//start reading packets from stream and write them to file
av_read_play(format_ctx); //play RTSP
// Get the codec
AVCodec *codec = NULL;
codec = avcodec_find_decoder(AV_CODEC_ID_H264);
if (!codec) {
exit(1);
}
// Add this to allocate the context by codec
codec_ctx = avcodec_alloc_context3(codec);
avcodec_get_context_defaults3(codec_ctx, codec);
avcodec_copy_context(codec_ctx, format_ctx->streams[video_stream_index]->codec);
std::ofstream output_file;
if (avcodec_open2(codec_ctx, codec, NULL) < 0)
exit(1);
img_convert_ctx = sws_getContext(codec_ctx->width, codec_ctx->height,
codec_ctx->pix_fmt, codec_ctx->width, codec_ctx->height, AV_PIX_FMT_RGB24,
SWS_BICUBIC, NULL, NULL, NULL);
int size = avpicture_get_size(AV_PIX_FMT_YUV420P, codec_ctx->width,
codec_ctx->height);
uint8_t* picture_buffer = (uint8_t*) (av_malloc(size));
AVFrame* picture = av_frame_alloc();
AVFrame* picture_rgb = av_frame_alloc();
int size2 = avpicture_get_size(AV_PIX_FMT_RGB24, codec_ctx->width,
codec_ctx->height);
uint8_t* picture_buffer_2 = (uint8_t*) (av_malloc(size2));
avpicture_fill((AVPicture *) picture, picture_buffer, AV_PIX_FMT_YUV420P,
codec_ctx->width, codec_ctx->height);
avpicture_fill((AVPicture *) picture_rgb, picture_buffer_2, AV_PIX_FMT_RGB24,
codec_ctx->width, codec_ctx->height);
while (av_read_frame(format_ctx, &packet) >= 0 && cnt < 1000) { //read ~ 1000 frames
std::cout << "1 Frame: " << cnt << std::endl;
if (packet.stream_index == video_stream_index) { //packet is video
std::cout << "2 Is Video" << std::endl;
if (stream == NULL) { //create stream in file
std::cout << "3 create stream" << std::endl;
stream = avformat_new_stream(output_ctx,
format_ctx->streams[video_stream_index]->codec->codec);
avcodec_copy_context(stream->codec,
format_ctx->streams[video_stream_index]->codec);
stream->sample_aspect_ratio =
format_ctx->streams[video_stream_index]->codec->sample_aspect_ratio;
}
int check = 0;
packet.stream_index = stream->id;
std::cout << "4 decoding" << std::endl;
int result = avcodec_decode_video2(codec_ctx, picture, &check, &packet);
std::cout << "Bytes decoded " << result << " check " << check
<< std::endl;
if (cnt > 100) //cnt < 0)
{
sws_scale(img_convert_ctx, picture->data, picture->linesize, 0,
codec_ctx->height, picture_rgb->data, picture_rgb->linesize);
std::stringstream file_name;
file_name << "test" << cnt << ".ppm";
output_file.open(file_name.str().c_str());
output_file << "P3 " << codec_ctx->width << " " << codec_ctx->height
<< " 255\n";
for (int y = 0; y < codec_ctx->height; y++) {
for (int x = 0; x < codec_ctx->width * 3; x++)
output_file
<< (int) (picture_rgb->data[0]
+ y * picture_rgb->linesize[0])[x] << " ";
}
output_file.close();
}
cnt++;
}
av_free_packet(&packet);
av_init_packet(&packet);
}
av_free(picture);
av_free(picture_rgb);
av_free(picture_buffer);
av_free(picture_buffer_2);
av_read_pause(format_ctx);
avio_close(output_ctx->pb);
avformat_free_context(output_ctx);
return (EXIT_SUCCESS);
}
please help me to compile this by C-compiler.
Related
sendmmsg/recvmmsg provide the option to send and receive multiple packets on socket in a single system call. Are these operations supported for TUN adaptor on Linux using C socket API.
Here is the sample code I tried but get errno=Socket operation on non-socket
struct mmsghdr hdrs[ARRAY_SIZE];
unsigned char data[ARRAY_SIZE][BUFF_SIZE];
struct iovec iovecs[ARRAY_SIZE];
memset(hdrs, 0, sizeof(hdrs));
for (int i = 0; i < ARRAY_SIZE; i++)
{
iovecs[i].iov_base = data[i];
iovecs[i].iov_len = BUFF_SIZE;
hdrs[i].msg_hdr.msg_iov = &iovecs[i];
hdrs[i].msg_hdr.msg_iovlen = 1;
}
while (true)
{
LOG_DEBUG(log__) << "blocking to read on fd=" << fd;
int retVal = recvmmsg(fd, hdrs, ARRAY_SIZE, 0, NULL);
LOG_DEBUG(log__) << "retVal=" << retVal;
if (retVal < 0)
{
LOG_ERROR(log__) << "failed in recvmmsg, retVal=" << retVal << ", errno=" << strerror(errno);
continue;
}
LOG_DEBUG(log__) << "read " << retVal << " messages";
for (int i = 0; i < retVal; i++)
{
LOG_DEBUG(log__) << "read data of length " << hdrs[i].msg_len;
}
}
I want to record a video from a V4L2 device (from the Raspberry Pi camera) in C.
The recording itself works and I can save the video to a file.
However I need to change the bitrate of the video. From the strace output of the v4l2-ctl --set-ctrl video_bitrate=10000000 command I know that the extended controls API of v4l2 is used to achieve this.
Here's my code which doesn't work so far:
#include <iostream>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <sys/mman.h> //mmap
#include <fcntl.h>
#include <unistd.h>
#include <linux/videodev2.h>
using namespace std;
#define numbuffers 3
struct picturebuffer
{
void *startadress;
size_t length;
};
//array in which the buffer pointer are being stored
picturebuffer pb[numbuffers];
int main()
{
//open camera
int fd;
fd = open("/dev/video0", O_RDWR);
if(fd < 0)
{
cout << "error during opening the camera device!";
cout.flush();
}
cout << "camera opened";
//read capabilities
struct v4l2_capability caps;
if(ioctl(fd, VIDIOC_QUERYCAP, &caps) < 0)
{
cout << "error while reading the capabilities!";
cout.flush();
}
cout << "Capabilities " << caps.capabilities << endl;
//ToDo: check for required capabilities
//set image data
struct v4l2_format format;
format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
format.fmt.pix.pixelformat = V4L2_PIX_FMT_H264;
format.fmt.pix.width = 1920;
format.fmt.pix.height = 1080;
if(ioctl(fd, VIDIOC_S_FMT, &format) < 0)
{
cout << "error in the image format";
}
cout << "Image properties set" << endl;
//Todo: check if width and height fit together (VIDIOC_ENUM_FRAMESIZES)
//set extended Controls
struct v4l2_ext_controls ecs;
struct v4l2_ext_control ec;
memset(&ecs, 0, sizeof(ecs));
memset(&ec, 0, sizeof(ec));
ec.id = V4L2_CID_MPEG_VIDEO_BITRATE;
ec.value = 10000000;
ec.size = 0;
ecs.controls = &ec;
ecs.count = 1;
ecs.ctrl_class = V4L2_CTRL_CLASS_MPEG;
if(ioctl(fd, VIDIOC_S_EXT_CTRLS, &ecs) < 0)
{
cout << "error in extended controls bitrate";
cout.flush();
}
//allocate buffer in the kernel
struct v4l2_requestbuffers req;
req.count = numbuffers;
req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
req.memory = V4L2_MEMORY_MMAP;
if(ioctl(fd, VIDIOC_REQBUFS, &req) < 0)
{
cout << "errro while allocating buffer";
cout.flush();
}
cout << "number of buffers: " << req.count << endl;
cout.flush();
//map buffers into userspace
for(int i=0; i<numbuffers; i++)
{
struct v4l2_buffer bufferinfo;
memset(&bufferinfo, 0, sizeof(bufferinfo));
bufferinfo.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
bufferinfo.memory = V4L2_MEMORY_MMAP;
bufferinfo.index = i;
if(ioctl(fd, VIDIOC_QUERYBUF, &bufferinfo) < 0)
{
cout << "error while querying bufferinfo";
cout.flush();
}
pb[i].startadress = mmap(NULL, bufferinfo.length, PROT_READ | PROT_WRITE, MAP_SHARED, fd, bufferinfo.m.offset);
pb[i].length = bufferinfo.length;
if(pb[i].startadress == MAP_FAILED)
{
cout << "error during mmap" << endl;
}
memset(pb[i].startadress, 0, bufferinfo.length);
cout << "size of buffer: " << bufferinfo.length << endl;
}
cout << "buffers mapped into userspace" << endl;
cout.flush();
//queue in the buffers
for(int i=0; i<numbuffers; i++)
{
struct v4l2_buffer bufferinfo;
memset(&bufferinfo, 0, sizeof(bufferinfo));
bufferinfo.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
bufferinfo.memory = V4L2_MEMORY_MMAP;
bufferinfo.index = i;
if(ioctl(fd, VIDIOC_QBUF, &bufferinfo) < 0)
{
cout << "error while queueing the buffers in" << endl;
}
}
//since that point the driver starts capturing the pics
int type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
if(ioctl(fd, VIDIOC_STREAMON, &type) < 0)
{
cout << "error while starting the stream" << endl;
}
int file;
if((file = open("/home/pi/image.h264", O_WRONLY | O_CREAT, 0660)) < 0)
{
cout << "error while writing the file";
}
//loop for managing the pics
for(int i=0; i<100; i++)
{
struct v4l2_buffer bufferinfo;
memset(&bufferinfo, 0, sizeof(bufferinfo));
bufferinfo.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
bufferinfo.memory = V4L2_MEMORY_MMAP;
if(ioctl(fd, VIDIOC_DQBUF, &bufferinfo) < 0)
{
cout << "error while getting the buffer!" << endl;
}
//do anything with the pic
char buf[pb[bufferinfo.index].length];
memcpy(&buf, pb[bufferinfo.index].startadress, pb[bufferinfo.index].length);
cout << bufferinfo.index << endl;
cout.flush();
//write picture into the file
write(file, pb[bufferinfo.index].startadress, pb[bufferinfo.index].length);
if(ioctl(fd, VIDIOC_QBUF, &bufferinfo) < 0)
{
cout << "error while enqueuing the buffer" << endl;
}
}
close(file);
if(ioctl(fd, VIDIOC_STREAMOFF, &type) < 0)
{
cout << "error while stopping the stream" << endl;
}
//clean up
for(int i=0; i<numbuffers; i++)
{
if(munmap(pb[i].startadress, pb[i].length) < 0)
{
cout << "error during unmap";
}
}
//close camera file
close(fd);
cout << "!!!Hello World!!!" << endl;
cout.flush();
return 0;
}
The ioctl call seems to succeed, however my output file always has the same size as of 199,2 MB. Does someone know what´s wrong in the code ?
You need to check if the camera driver supports that IOCTL command. If the driver doesn't support the IOCTL command by not implementing it, you still can execute the command and it is routed to v4l2 default implementation, no actual changes are applied to the camera setting
Try to change the lines:
pb[bufferinfo.index].length
By:
pb[bufferinfo.index].bytesused
For example:
write(file, pb[bufferinfo.index].startadress, pb[bufferinfo.index].bytesused);
I can't get libbz2 to work. After 10 000 characters it terminates with end of stream although the input file contains several gigabytes. I just cannot figure out what goes wrong. Thank you for any remarks.
Here is my code:
string read_bz2_file(const string& filename) {
string result;
FILE* f;
BZFILE* b;
const int BUFSIZE = 1000;
char buf[BUFSIZE];
int bzerror;
f = fopen(filename.c_str(), "r");
if (!f) {
/* handle error */
cerr << "cannot read file " << filename << endl;
return "";
}
b = BZ2_bzReadOpen(&bzerror, f, 0, 0, NULL, 0);
if (bzerror != BZ_OK) {
BZ2_bzReadClose(&bzerror, b);
cerr << "cannot read file " << filename << endl;
return "";
/* handle error */
}
bzerror = BZ_OK;
while (bzerror == BZ_OK /* arbitrary other conditions */) {
BZ2_bzRead(&bzerror, b, buf, BUFSIZE /* size of buf */);
cout << "bzerror: " << bzerror << endl;
if (bzerror == BZ_OK) {
/* do something with buf[0 .. nBuf-1] */
result.append(buf);
}
}
if (bzerror != BZ_STREAM_END) {
BZ2_bzReadClose(&bzerror, b);
cerr << "error while reading file " << filename << endl;
return "";
/* handle error */
} else {
result.append(buf);
BZ2_bzReadClose(&bzerror, b);
return result;
}
return result;
}
You can try to open the file in binary mode, adding a "b" to the fopen mode:
f = fopen(filename.c_str(), "rb");
so I'm new to socket programming, and I was asked to write the server side that sends data to a client according to a certain request. I'm trying to server multiple clients at the same time. When a client first connects, the server accepts with no troubles whatsoever, but when a client sends a certain request, I get stuck in an infinity loop and it's not clear at all to me why the server keeps sending the same info to the client over and over and over again, below is my code for the server side:
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include <math.h>
#include <windows.h>
#include <winsock.h>
#include <string.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <io.h>
#include <fstream>
#include <vector>
#define MAX_CONNECTION 100
#ifndef max
#define max(a,b) ((a) < (b) ? (a) : (b))
#endif
typedef struct connection{
char ipaddr[16];
int port;
int sd;
} connection;
static unsigned short SERVER_PORT = 4118;
int main(int argc, char* argv[])
{
int maxfd =-1;
fd_set rset, allset;
connection client[MAX_CONNECTION];
int passiveSock; /* Main Server Socket */
struct sockaddr_in servSock_in;
#ifdef WIN32
WSADATA wsaData;
WSAStartup(0x0101, &wsaData);
#endif
int port;
if (argc > 1)
port = atoi(argv[1]);
else
port = SERVER_PORT;
for(int i=0; i < MAX_CONNECTION ; i++)
client[i].sd = -1;
memset((char *)&servSock_in, 0, sizeof(servSock_in));
servSock_in.sin_family = PF_INET;
servSock_in.sin_addr.s_addr = htonl(INADDR_ANY);
servSock_in.sin_port = htons((u_short)port);
passiveSock = socket(PF_INET, SOCK_STREAM, 0);
if (passiveSock < 0) {
fprintf(stderr, "I am too tired... I failed to open gate...\n");
return -1;
}
if (bind(passiveSock, (struct sockaddr *)&servSock_in, sizeof(servSock_in)) < 0){
fprintf(stderr, "I couldn't attach gate to port...\n");
return -1;
}
if (listen(passiveSock, 5) < 0) {
fprintf(stderr, "I am not hearing anything...\n");
return -1;
}
FD_SET(passiveSock, &allset);
maxfd = max(maxfd, passiveSock);
struct sockaddr_in cliSock_in;
int cliSockLen;
int connectedSock;
cliSockLen = sizeof(cliSock_in);
printf("\n Waiting for an incoming connection at port number %d", port);
int bytesread = 0;
for (;;)
{
//FD_ZERO(&allset);
rset = allset;
int nready = select(maxfd+1,&rset, NULL, NULL, NULL);
if(FD_ISSET(passiveSock, &rset)){
printf("In the first if");
connectedSock = accept(passiveSock, (struct sockaddr *)&cliSock_in, &cliSockLen);
/* if an error occurs while accepting */
if (connectedSock == -1) {
printf("\n Server: Accept error (errno = %d: %s)\n", errno, strerror(errno));
continue;
}
for (int i=0; i<MAX_CONNECTION; i++)
if (client[i].sd < 0){
client[i].sd=connectedSock;
strcpy(client[i].ipaddr, inet_ntoa(cliSock_in.sin_addr));
client[i].port= ntohs(cliSock_in.sin_port);
printf("\n Server: connection established with %s:%d\n",
client[i].ipaddr, client[i].port);
break;
}
FD_SET(connectedSock, &allset);
maxfd = max(maxfd, connectedSock);
}
else{
for(int j = 0 ; j < MAX_CONNECTION; j++){
connectedSock = client[j].sd;
printf("connectedSock is %d", connectedSock);
if(connectedSock < 0)
continue;
if(FD_ISSET(client[j].sd, &rset)){
unsigned char buffer[66000];
int index = 0;
bytesread = recv(connectedSock, (char *)buffer, 66000, 0);
int type;
type = (buffer[0] & 0xE0) >> 5;
if (type == 0)
{
char fname[100];
int i = 0;
int length = (buffer[i++] & 0x1F);
memcpy(&fname[0], &buffer[i], length);
fname[length] = '\0';
i += length;
int fs = 0;
fs += (buffer[i++] << 8) & 0xff00;
fs += buffer[i++];
char* filedata = (char*)malloc(fs*sizeof(char));
memcpy(&filedata[0], &buffer[i], fs);
filedata[fs] = '\0';
for (int i = 0; i < fs; i++)
printf("%c", filedata[i]);
printf("type=%d,length=%d,data=%s,fs=%d,filedata=%s", type, length, fname, fs, filedata);
std::ofstream of;
of.open(fname, std::ios::binary);
for (int i = 0; i < fs; i++)
of.write(filedata + i, 1);
of.close();
unsigned char rep;
int reptype = 0;
rep = (unsigned char)(reptype & 0x07);
send(connectedSock, (char*)(&rep), 1, 0);
}
else if (type == 1)
{
char fname[100];
int i = 0;
int length = (buffer[i++] & 0x1F);
memcpy(&fname[0], &buffer[i], length);
fname[length] = '\0';
i += length;
std::ifstream t;
int fs;
t.open(fname, std::ios::binary);
std::vector<char> vec((
std::istreambuf_iterator<char>(t)),
(std::istreambuf_iterator<char>()));// open input file
t.close();
fs = vec.size();
char* filedata = (char*)malloc(fs*sizeof(char)); // allocate memory for a buffer of appropriate dimension
filedata = &vec[0];
filedata[fs] = '\0';
i = 0;
unsigned char* repbuffer = (unsigned char*)malloc(3 + length + fs);
repbuffer[i] = (unsigned char)(type & 0x07);
repbuffer[i] = repbuffer[i] << 5;
repbuffer[i] = repbuffer[i] | (length & 0x0000003F);
i++;
memcpy(&repbuffer[i], fname, length);
i = i + length;
printf("sizeof fs=%d", sizeof(fs));
repbuffer[i++] = (unsigned char)((fs & 0xff00) >> 8);
repbuffer[i++] = (unsigned char)(fs & 0xff);
memcpy(&repbuffer[i], filedata, fs);
printf("sizeof buffer=%d", sizeof(repbuffer));
i = i + fs;
// printf("the buffer contains %s\n",&repbuffer[11]);
if (send(connectedSock, (char*)repbuffer, i, 0) == -1)
{
printf("A local error was detected while sending data! (errno = %d: %s)\n", errno, strerror(errno));
return -1;
}
}
else if (type == 2)
{
char fname[100],nfname[100];
int i = 0;
int length = (buffer[i++] & 0x1F);
memcpy(&fname[0], &buffer[i], length);
fname[length] = '\0';
i += length;
int nlength = (buffer[i++] & 0x1F);
memcpy(&nfname[0], &buffer[i], nlength);
nfname[nlength] = '\0';
rename(fname,nfname);
}
else if (type == 3)
{
char rep[32];
strcpy(rep, "bye change get help put");
int length = strlen(rep);
unsigned char* repbuffer = (unsigned char*)malloc(1 + length);
int type = 6;
repbuffer[0] = (unsigned char)(type & 0x07);
repbuffer[0] = repbuffer[0] << 5;
repbuffer[0] = repbuffer[0] | (length & 0x0000003F);
memcpy(&repbuffer[1], rep, length);
if (send(connectedSock, (char*)repbuffer, length+1, 0) == -1)
{
perror("A local error was detected while sending data!!");
return -1;
}
}
else if (type == 4)
{
closesocket(connectedSock);
}
break;
}
}
}
}
closesocket(passiveSock);
WSACleanup();
return 0;
}
I feel there's something wrong with the usage of FD_ISSET() method, I've been trying to figure out the error for 2 hours now, pleeassse help
I'm trying to make a simple C program play an AIFF or WAV file. Based on what I see at http://www.xiph.org/ao/doc/, this should work, but instead it makes a buzzing sound no matter what file I feed it. What's wrong with this?
/* compile with "gcc -o playme playme.c -lao -ldl -lm" */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ao/ao.h>
#include <math.h>
ao_device *device;
ao_sample_format format;
int main(int argc, char *argv[])
{
int default_driver;
char *buffer;
unsigned long count;
FILE *fp;
if (argc != 2) {
printf("usage: %s <filename>\n", argv[0]);
exit(1);
}
ao_initialize();
default_driver = ao_default_driver_id();
memset(&format, 0, sizeof(format));
format.bits = 16;
format.channels = 2;
format.rate = 44100;
format.byte_format = AO_FMT_LITTLE;
device = ao_open_live(default_driver, &format, NULL /* no options */);
if (device == NULL) {
printf("Error opening sound device.\n");
exit(1);
}
fp = fopen(argv[1], "rb");
if (fp == NULL) {
printf("Cannot open %s.\n", argv[1]);
exit(2);
}
fseek(fp, 0, SEEK_END);
count = ftell(fp);
fseek(fp, 0, SEEK_SET);
fread(buffer, sizeof(char), count, fp);
ao_play(device, buffer, count);
ao_close(device);
ao_shutdown();
return 0;
}
A critical something I didn't realize is that libao does absolutely no decoding. It is therefore up to the programmer to extract the sample size, rate, channels, etc and feed those to libao before opening the audio device. libsndfile is available for doing this, but if you just want something quick and dirty, here's the code for playing an AIFF file:
/* compile with "gcc -o playaiff playaiff.c -lao -ldl -lm" */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ao/ao.h>
#include <math.h>
#define MAXCHAN 8
ao_device *device;
ao_sample_format format;
#define gshort( b) (((int)((b)[0]) << 8) + (int)((b)[1]))
#define glong( b) (((int)((b)[0]) << 24) + ((int)((b)[1]) << 16) +\
((int)((b)[2]) << 8) + (int)((b)[3]))
typedef struct {
short channels;
short samplesize;
int samplerate;
unsigned long samplecount;
int valid;
} aiffinfo;
aiffinfo getaiffinfo(FILE *);
static int IeeeExtendedToLong(unsigned char *);
int main(int argc, char *argv[])
{
int default_driver;
char *buffer;
aiffinfo info;
FILE *fp;
if (argc != 2) {
printf("usage: %s <filename>\n", argv[0]);
exit(1);
}
ao_initialize();
default_driver = ao_default_driver_id();
memset(&format, 0, sizeof(format));
fp = fopen(argv[1], "rb");
if (fp == NULL) {
printf("Cannot open %s.\n", argv[1]);
exit(2);
}
info = getaiffinfo(fp);
if (!info.valid) {
printf("Invalid AIFF file.\n");
exit(1);
}
format.bits = info.samplesize;
format.channels = info.channels;
format.rate = info.samplerate;
format.byte_format = AO_FMT_LITTLE;
device = ao_open_live(default_driver, &format, NULL /* no options */);
if (device == NULL) {
printf("Error opening sound device.\n");
exit(1);
}
buffer = malloc(sizeof(char) * info.samplecount);
fread(buffer, sizeof(char), info.samplecount, fp);
ao_play(device, buffer, info.samplecount);
ao_close(device);
ao_shutdown();
return 0;
}
aiffinfo getaiffinfo(FILE *fp)
{
int size;
int len;
int offset;
int blocksize;
int found = 0;
unsigned char chunk[18];
unsigned char fid[4];
aiffinfo info;
info.samplesize = 0;
info.valid = 0;
if (fread(chunk, 1, 4, fp) < 4) return info;
if (memcmp(chunk,"FORM",4)) return info;
if (fread(chunk, 1, 4, fp) < 4) return info;
size = glong(chunk);
if (size & 1) size++;
if (size < 20) return info;
if (fread(chunk, 1, 4, fp) < 4) return info;
if (memcmp(chunk, "AIFF", 4)) return info;
size -= 4;
while (size > 8) {
if (fread(fid, 1, 4, fp) < 4) return info; // chunck id
if (fread(chunk, 1, 4, fp) < 4) return info; // and len
size -= 8;
len = glong(chunk);
if (len < 0) return info;
if (len & 1) len++;
size -= len;
if (size < 0) return info;
if (memcmp(fid, "COMM", 4) == 0) {
if (len != 18) return info;
if (fread(chunk, 1, 18, fp) < 18) return info;
info.channels = gshort(chunk);
if (info.channels < 1) return info;
if (info.channels > MAXCHAN) return info;
info.samplecount = glong(chunk+2);
if (info.samplecount < 1) return info;
info.samplerate = IeeeExtendedToLong(chunk + 8);
if (info.samplerate <= 0) return info;
info.samplesize = gshort(chunk + 6);
if (info.samplesize < 1 || info.samplesize > 16) return info;
} else if (memcmp(fid,"SSND",4)==0){
if (!info.channels) return info;
if (fread(chunk, 1, 4, fp) < 4) return info;
offset = glong(chunk);
if (fread(chunk, 1, 4, fp) < 4) return info;
blocksize = glong(chunk);
if (blocksize) return info;
if (offset) fseek(fp, offset,SEEK_CUR);
found = 1;
break;
} else fseek (fp, len, SEEK_CUR);
}
if (!found) return info;
if (!info.channels) return info;
// printf("Looks good so far.\n");
info.valid = 1;
return info;
}
/****************************************************************
* Extended precision IEEE floating-point conversion routine.
****************************************************************/
#ifndef Uint32
#define Uint32 unsigned int
#endif
#ifndef HUGE_INT32
#define HUGE_INT32 0x7fffffff
#endif /* HUGE_VAL */
static int IeeeExtendedToLong( unsigned char *bytes)
{
int f = 0;
int expon;
Uint32 hiMant;
Uint32 loMant;
expon = ((bytes[0] & 0x7F) << 8) | (bytes[1] & 0xFF);
hiMant = ((Uint32) (bytes[2] & 0xFF) << 24)
| ((Uint32) (bytes[3] & 0xFF) << 16)
| ((Uint32) (bytes[4] & 0xFF) << 8)
| ((Uint32) (bytes[5] & 0xFF));
loMant = ((Uint32) (bytes[6] & 0xFF) << 24)
| ((Uint32) (bytes[7] & 0xFF) << 16)
| ((Uint32) (bytes[8] & 0xFF) << 8)
| ((Uint32) (bytes[9] & 0xFF));
if (expon == 0 && hiMant == 0 && loMant == 0) f = 0;
else if (expon == 0x7FFF) f = HUGE_INT32;
else {
expon -= 16382;
expon = 32-expon;
if (expon < 0) f = HUGE_INT32;
else f = hiMant >> expon;
}
if (bytes[0] & 0x80)
return -f;
else
return f;
}