mediaextract/audioextract.c

236 lines
3.9 KiB
C
Raw Normal View History

2012-12-26 21:08:18 +00:00
/*
* audioextract
2012-12-26 21:08:18 +00:00
*
* Author: Mathaias Panzenböck
* This is derived from oggextract:
* http://ner.mine.nu/oggextract/
*
* Original author of oggextract: Adrian Keet
2012-12-26 21:08:18 +00:00
*/
2012-12-27 16:02:19 +00:00
#include "audioextract.h"
#include "wave.h"
#include "ogg.h"
2012-12-27 03:58:43 +00:00
enum fileformat {
NONE = 0,
OGG = 1,
RIFF = 2,
AIFF = 3
/* TODO: MP3, AAC and MKV? */
};
int usage(int argc, char **argv)
2012-12-26 21:08:18 +00:00
{
2012-12-27 16:02:19 +00:00
fprintf(stderr, "Usage: %s <filename> [<filename> ...]\n",
argc <= 0 ? "audioextract" : argv[0]);
2012-12-26 21:08:18 +00:00
return 255;
}
2012-12-27 03:58:43 +00:00
const unsigned char *findmagic(const unsigned char *start, const unsigned char *end, enum fileformat *format)
2012-12-26 21:08:18 +00:00
{
if (end < (unsigned char *)4)
2012-12-27 03:58:43 +00:00
return NULL;
2012-12-27 01:05:02 +00:00
end -= 4;
for (; start < end; ++ start)
{
2012-12-27 03:58:43 +00:00
switch (*(const int32_t *)start)
{
case OGG_MAGIC:
*format = OGG;
return start;
case RIFF_MAGIC:
*format = RIFF;
return start;
case FORM_MAGIC:
*format = AIFF;
return start;
}
2012-12-27 01:05:02 +00:00
}
2012-12-26 21:08:18 +00:00
2012-12-27 01:05:02 +00:00
return NULL;
2012-12-26 21:08:18 +00:00
}
2012-12-27 01:05:02 +00:00
const char *basename(const char *path)
2012-12-26 21:08:18 +00:00
{
2012-12-27 01:05:02 +00:00
const char *ptr = strrchr(path, '/');
2012-12-27 03:58:43 +00:00
#ifdef __WINDOWS__
2012-12-27 01:05:02 +00:00
/* Windows supports both / and \ */
const char *ptr2 = strrchr(path, '\\');
2012-12-27 01:05:02 +00:00
if (ptr2 > ptr)
ptr = ptr2;
#endif
return ptr ? ptr + 1 : path;
2012-12-26 21:08:18 +00:00
}
2012-12-27 01:05:02 +00:00
int extract(const char *filepath, size_t *numfilesptr)
2012-12-26 21:08:18 +00:00
{
2012-12-27 01:05:02 +00:00
int fd = -1;
2012-12-26 21:08:18 +00:00
struct stat statdata;
2012-12-27 01:05:02 +00:00
size_t filesize = 0;
unsigned char *filedata = NULL;
const unsigned char *ptr = NULL, *end = NULL;
2012-12-27 03:58:43 +00:00
enum fileformat format = NONE;
2012-12-26 21:08:18 +00:00
2012-12-27 03:58:43 +00:00
size_t length = 0;
2012-12-26 21:08:18 +00:00
int outfd = -1;
2012-12-27 01:05:02 +00:00
int success = 1;
char *outfilename = NULL;
size_t numfiles = 0;
const char *filename = basename(filepath);
size_t namelen = strlen(filename) + 22;
2012-12-26 21:08:18 +00:00
2012-12-27 01:05:02 +00:00
printf("Extracting %s\n", filepath);
2012-12-26 21:08:18 +00:00
2012-12-27 01:05:02 +00:00
fd = open(filepath, O_RDONLY);
if (fd < 0)
2012-12-26 21:08:18 +00:00
{
2012-12-27 01:05:02 +00:00
perror("open");
2012-12-27 16:02:19 +00:00
goto error;
2012-12-26 21:08:18 +00:00
}
2012-12-27 01:05:02 +00:00
if (fstat(fd, &statdata) < 0)
2012-12-26 21:08:18 +00:00
{
2012-12-27 01:05:02 +00:00
perror("stat");
2012-12-27 16:02:19 +00:00
goto error;
2012-12-26 21:08:18 +00:00
}
2012-12-27 01:05:02 +00:00
if (S_ISDIR(statdata.st_mode))
2012-12-26 21:08:18 +00:00
{
2012-12-27 01:05:02 +00:00
fprintf(stderr, "error: Is a directory: %s\n", filepath);
2012-12-27 16:02:19 +00:00
goto error;
2012-12-26 21:08:18 +00:00
}
2012-12-27 01:05:02 +00:00
filesize = statdata.st_size;
2012-12-26 21:08:18 +00:00
filedata = mmap(0, filesize, PROT_READ, MAP_PRIVATE, fd, 0);
2012-12-27 03:58:43 +00:00
if (filedata == MAP_FAILED)
{
2012-12-27 01:05:02 +00:00
perror("mmap");
2012-12-27 16:02:19 +00:00
goto error;
2012-12-27 01:05:02 +00:00
}
2012-12-26 21:08:18 +00:00
2012-12-27 01:05:02 +00:00
outfilename = malloc(namelen);
2012-12-27 03:58:43 +00:00
if (outfilename == NULL)
{
2012-12-27 01:05:02 +00:00
perror("malloc");
2012-12-27 16:02:19 +00:00
goto error;
2012-12-27 01:05:02 +00:00
}
2012-12-26 21:08:18 +00:00
2012-12-27 03:58:43 +00:00
#define OPEN_OUTFD(ext) \
snprintf(outfilename, namelen, "%s_%08zx.%s", filename, (size_t)(ptr - filedata), ext); \
2012-12-27 03:58:43 +00:00
outfd = creat(outfilename, -1); \
if (outfd < 0) \
{ \
perror("creat"); \
2012-12-27 16:02:19 +00:00
goto error; \
2012-12-27 03:58:43 +00:00
} \
++ numfiles; \
2012-12-27 03:58:43 +00:00
printf("Writing: %s\n", outfilename)
2012-12-27 01:05:02 +00:00
ptr = filedata;
2012-12-27 03:58:43 +00:00
for (end = filedata + filesize; (ptr = findmagic(ptr, end, &format));)
2012-12-26 21:08:18 +00:00
{
2012-12-27 03:58:43 +00:00
switch (format)
2012-12-26 21:08:18 +00:00
{
2012-12-27 03:58:43 +00:00
case OGG:
if (ogg_ispage(ptr, end, &length) && ogg_isinitial(ptr))
{
OPEN_OUTFD("ogg");
do {
write(outfd, ptr, length);
ptr += length;
} while (ptr < end && ogg_ispage(ptr, end, &length));
close(outfd);
continue;
}
break;
2012-12-26 21:08:18 +00:00
2012-12-27 03:58:43 +00:00
case RIFF:
if (wave_ischunk(ptr, end, &length))
2012-12-27 01:05:02 +00:00
{
2012-12-27 03:58:43 +00:00
OPEN_OUTFD("wav");
write(outfd, ptr, length);
ptr += length;
close(outfd);
continue;
2012-12-27 01:05:02 +00:00
}
2012-12-27 03:58:43 +00:00
break;
case AIFF:
if (aiff_ischunk(ptr, end, &length))
{
OPEN_OUTFD("aif");
write(outfd, ptr, length);
ptr += length;
close(outfd);
continue;
}
break;
case NONE:
break;
2012-12-26 21:08:18 +00:00
}
2012-12-27 03:58:43 +00:00
ptr += 4;
}
2012-12-27 01:05:02 +00:00
2012-12-27 16:02:19 +00:00
goto cleanup;
error:
success = 0;
cleanup:
if (outfilename)
free(outfilename);
2012-12-27 01:05:02 +00:00
2012-12-27 16:02:19 +00:00
if (filedata)
munmap(filedata, filesize);
2012-12-27 01:05:02 +00:00
2012-12-27 16:02:19 +00:00
if (fd >= 0)
close(fd);
2012-12-26 21:08:18 +00:00
2012-12-27 01:05:02 +00:00
if (numfilesptr)
*numfilesptr = numfiles;
2012-12-26 21:08:18 +00:00
2012-12-27 01:05:02 +00:00
return success;
2012-12-26 21:08:18 +00:00
}
int main(int argc, char **argv)
{
2012-12-27 01:05:02 +00:00
int i = 0;
size_t failures = 0;
size_t sumnumfiles = 0;
size_t numfiles = 0;
2012-12-26 21:08:18 +00:00
if (argc < 2)
return usage(argc, argv);
2012-12-26 21:08:18 +00:00
failures = 0;
2012-12-27 01:05:02 +00:00
for (i = 1; i < argc; ++i)
{
if (extract(argv[i], &numfiles))
{
sumnumfiles += numfiles;
}
else {
fprintf(stderr, "Error processing file: %s\n", argv[i]);
failures += 1;
}
}
printf("Extracted %lu file(s).\n", numfiles);
2012-12-26 21:08:18 +00:00
if (failures > 0)
2012-12-27 01:05:02 +00:00
{
fprintf(stderr, "%zu error(s) during extraction.\n", failures);
2012-12-27 01:05:02 +00:00
return 1;
}
return 0;
2012-12-26 21:08:18 +00:00
}