Audio import: separate WAV header reader

This commit is contained in:
Martin Pulec
2013-05-01 12:47:48 +02:00
parent f76f7ff037
commit 751de23f14
4 changed files with 128 additions and 58 deletions

View File

@@ -71,6 +71,7 @@ OBJS = @OBJS@ \
src/audio/playback/sdi.o \
src/audio/resampler.o \
src/audio/utils.o \
src/audio/wav_reader.o \
@COREAUDIO_OBJ@ \
@JACK_TRANS_OBJ@ \
@SPEEX_OBJ@ \

79
src/audio/wav_reader.c Normal file
View File

@@ -0,0 +1,79 @@
#ifdef HAVE_CONFIG_H
#include "config.h"
#include "config_unix.h"
#include "config_win32.h"
#endif // HAVE_CONFIG_H
#include "audio/wav_reader.h"
#define READ_N(buf, len) if (fread(buf, len, 1, wav_file) != 1) return WAV_HDR_PARSE_READ_ERROR;
int read_wav_header(FILE *wav_file, struct wav_metadata *metadata)
{
char buffer[16];
rewind(wav_file);
READ_N(buffer, 4);
if(strncmp(buffer, "RIFF", 4) != 0) {
return WAV_HDR_PARSE_WRONG_FORMAT;
}
uint32_t chunk_size;
READ_N(&chunk_size, 4);
READ_N(buffer, 4);
if(strncmp(buffer, "WAVE", 4) != 0) {
return WAV_HDR_PARSE_WRONG_FORMAT;
}
// format chunk
READ_N(buffer, 4);
if(strncmp(buffer, "fmt ", 4) != 0) {
return WAV_HDR_PARSE_WRONG_FORMAT;
}
uint32_t fmt_chunk_size;
READ_N(&fmt_chunk_size, 4);
if(fmt_chunk_size != 16) {
return WAV_HDR_PARSE_WRONG_FORMAT;
}
uint16_t format;
READ_N(&format, 2);
if(format != 0x0001) {
return WAV_HDR_PARSE_NOT_PCM;
}
uint16_t ch_count;
READ_N(&ch_count, 2);
metadata->ch_count = ch_count;
uint32_t sample_rate;
READ_N(&sample_rate, sizeof(sample_rate));
metadata->sample_rate = sample_rate;
uint32_t avg_bytes_per_sec;
READ_N(&avg_bytes_per_sec, sizeof(avg_bytes_per_sec));
uint16_t block_align_offset;
READ_N(&block_align_offset, sizeof(block_align_offset));
uint16_t bits_per_sample;
READ_N(&bits_per_sample, sizeof(bits_per_sample));
metadata->bits_per_sample = bits_per_sample;
// data chunk
READ_N(buffer, 4);
if(strncmp(buffer, "data", 4) != 0) {
return WAV_HDR_PARSE_WRONG_FORMAT;
}
uint32_t data_chunk_size;
READ_N(&data_chunk_size, 4);
metadata->data_size = data_chunk_size;
metadata->data_offset = ftell(wav_file);
return WAV_HDR_PARSE_OK;
}

28
src/audio/wav_reader.h Normal file
View File

@@ -0,0 +1,28 @@
#include <stdio.h> // FILE *
struct wav_metadata {
int ch_count;
int sample_rate;
int bits_per_sample;
int data_size;
int data_offset; // from the beginning of file
};
#define WAV_HDR_PARSE_OK 0
#define WAV_HDR_PARSE_READ_ERROR 1
#define WAV_HDR_PARSE_WRONG_FORMAT 2
#define WAV_HDR_PARSE_NOT_PCM 3
/**
* This function reads wav header
*
* If read successfully, it leaves read file position at the beginning of data.
* Currently, only interleaved PCM is supported.
*
* @retval WAV_HDR_PARSE_OK if ok
* @retval WAV_HDR_PARSE_READ_ERROR in case of file read error
* @retval WAV_HDR_PARSE_WRONG_FORMAT if unsupported wav format
* @retval WAV_HDR_PARSE_NOT_PCM non-PCM WAV detected
*/
int read_wav_header(FILE *wav_file, struct wav_metadata *metadata);

View File

@@ -58,6 +58,7 @@
#include "tv.h"
#include "audio/audio.h"
#include "audio/wav_reader.h"
#include "utils/ring_buffer.h"
#include "video_export.h"
#include "video_capture/import.h"
@@ -218,72 +219,33 @@ static bool init_audio(struct vidcap_import_state *s, char *audio_filename)
perror("Cannot open audio file");
return false;
}
char buffer[16];
// common commands - will run in any way
if(!audio_file) {
goto error_opening;
}
READ_N(buffer, 4);
if(strncmp(buffer, "RIFF", 4) != 0) {
goto error_format;
struct wav_metadata metadata;
int ret = read_wav_header(audio_file, &metadata);
switch(ret) {
case WAV_HDR_PARSE_READ_ERROR:
fprintf(stderr, "Error reading WAV header!\n");
goto error_format;
case WAV_HDR_PARSE_WRONG_FORMAT:
fprintf(stderr, "Unsupported WAV format!\n");
goto error_format;
case WAV_HDR_PARSE_NOT_PCM:
fprintf(stderr, "Only supported audio format is PCM.\n");
goto error_format;
case WAV_HDR_PARSE_OK:
break;
}
uint32_t chunk_size;
READ_N(&chunk_size, 4);
READ_N(buffer, 4);
if(strncmp(buffer, "WAVE", 4) != 0) {
goto error_format;
}
// format chunk
READ_N(buffer, 4);
if(strncmp(buffer, "fmt ", 4) != 0) {
goto error_format;
}
uint32_t fmt_chunk_size;
READ_N(&fmt_chunk_size, 4);
if(fmt_chunk_size != 16) {
goto error_format;
}
uint16_t format;
READ_N(&format, 2);
if(format != 0x0001) {
fprintf(stderr, "Only supported audio format is PCM.\n");
goto error_format;
}
uint16_t ch_count;
READ_N(&ch_count, 2);
s->audio_frame.ch_count = ch_count;
uint32_t sample_rate;
READ_N(&sample_rate, sizeof(sample_rate));
s->audio_frame.sample_rate = sample_rate;
uint32_t avg_bytes_per_sec;
READ_N(&avg_bytes_per_sec, sizeof(avg_bytes_per_sec));
uint16_t block_align_offset;
READ_N(&block_align_offset, sizeof(block_align_offset));
uint16_t bits_per_sample;
READ_N(&bits_per_sample, sizeof(bits_per_sample));
s->audio_frame.bps = bits_per_sample / 8;
// data chunk
READ_N(buffer, 4);
if(strncmp(buffer, "data", 4) != 0) {
goto error_format;
}
uint32_t data_chunk_size;
READ_N(&data_chunk_size, 4);
s->audio_state.total_samples = data_chunk_size / s->audio_frame.bps / s->audio_frame.ch_count;
s->audio_frame.ch_count = metadata.ch_count;
s->audio_frame.sample_rate = metadata.sample_rate;
s->audio_frame.bps = metadata.bits_per_sample / 8;
s->audio_state.total_samples = metadata.data_size / s->audio_frame.bps / s->audio_frame.ch_count;
s->audio_state.samples_read = 0;
s->audio_state.data = ring_buffer_init(s->audio_frame.bps * s->audio_frame.sample_rate *