1 /*
2 ogmmerge -- utility for splicing together ogg bitstreams
3 from component media subtypes
4
5 r_wav.cpp
6 WAVE demultiplexer module (supports raw / uncompressed PCM audio only,
7 type 0x0001)
8
9 Written by Moritz Bunkus <moritz@bunkus.org>
10 Based on Xiph.org's 'oggmerge' found in their CVS repository
11 See http://www.xiph.org
12
13 Distributed under the GPL
14 see the file COPYING for details
15 or visit http://www.gnu.org/copyleft/gpl.html
16 */
17
18 #include <stdlib.h>
19 #include <stdio.h>
20 #include <string.h>
21 #include <errno.h>
22
23 #include <ogg/ogg.h>
24
25 extern "C" {
26 #include <avilib.h> // for wave_header
27 }
28
29 #include "ogmmerge.h"
30 #include "ogmstreams.h"
31 #include "queue.h"
32 #include "r_wav.h"
33
probe_file(FILE * file,off_t size)34 int wav_reader_c::probe_file(FILE *file, off_t size) {
35 wave_header wheader;
36 if (size < sizeof(wave_header))
37 return 0;
38 if (fseeko(file, 0, SEEK_SET) != 0)
39 return 0;
40 if (fread((char *)&wheader, 1, sizeof(wheader), file) != sizeof(wheader)) {
41 fseeko(file, 0, SEEK_SET);
42 return 0;
43 }
44 fseeko(file, 0, SEEK_SET);
45 if (strncmp((char *)wheader.riff.id, "RIFF", 4) ||
46 strncmp((char *)wheader.riff.wave_id, "WAVE", 4) ||
47 strncmp((char *)wheader.data.id, "data", 4))
48 return 0;
49 return 1;
50 }
51
wav_reader_c(char * fname,audio_sync_t * nasync,range_t * nrange,char ** ncomments)52 wav_reader_c::wav_reader_c(char *fname, audio_sync_t *nasync,
53 range_t *nrange, char **ncomments) throw (error_c) {
54 uint64_t size;
55 uint32_t samplerate;
56 uint16_t channels, bitdepth;
57
58 if ((file = fopen(fname, "r")) == NULL)
59 throw error_c("wav_reader: Could not open source file.");
60 if (fseeko(file, 0, SEEK_END) != 0)
61 throw error_c("wav_reader: Could not seek to end of file.");
62 size = ftello(file);
63 if (fseeko(file, 0, SEEK_SET) != 0)
64 throw error_c("wav_reader: Could not seek to beginning of file.");
65 if (!wav_reader_c::probe_file(file, size))
66 throw error_c("wav_reader: Source is not a valid WAVE file.");
67 if (fread(&wheader, 1, sizeof(wheader), file) != sizeof(wheader))
68 throw error_c("wav_reader: could not read WAVE header.");
69 bps = get_uint16(&wheader.common.wChannels) *
70 get_uint16(&wheader.common.wBitsPerSample) *
71 get_uint32(&wheader.common.dwSamplesPerSec) / 8;
72 chunk = (unsigned char *)malloc(bps + 1);
73 if (chunk == NULL)
74 die("malloc");
75 bytes_processed = 0;
76 samplerate = get_uint32(&wheader.common.dwSamplesPerSec);
77 channels = get_uint16(&wheader.common.wChannels);
78 bitdepth = get_uint16(&wheader.common.wBitsPerSample);
79 pcmpacketizer = new pcm_packetizer_c(samplerate, channels, bitdepth, nasync,
80 nrange, ncomments);
81 if (verbose)
82 fprintf(stderr, "Using WAV demultiplexer for %s.\n+-> Using " \
83 "PCM output module for audio stream.\n", fname);
84 }
85
~wav_reader_c()86 wav_reader_c::~wav_reader_c() {
87 if (file != NULL)
88 fclose(file);
89 if (chunk != NULL)
90 free(chunk);
91 if (pcmpacketizer != NULL)
92 delete pcmpacketizer;
93 }
94
read()95 int wav_reader_c::read() {
96 int nread, last_frame;
97
98 if (pcmpacketizer->page_available())
99 return EMOREDATA;
100
101 nread = fread(chunk, 1, bps, file);
102 if (nread <= 0) {
103 /*
104 * In case that the WAVE header is not set correctly or any other error
105 * occurs. The 'normal' end-of-stream should be handled by comparing the
106 * number of bytes read to the WAVE header fields.
107 */
108 *chunk = 0;
109 pcmpacketizer->process((char *)chunk, 1, 1);
110 pcmpacketizer->flush_pages();
111 return 0;
112 }
113 last_frame = 0;
114 if ((bytes_processed + nread) >=
115 (get_uint32(&wheader.riff.len) - sizeof(wave_header) + 8))
116 last_frame = 1;
117 pcmpacketizer->process((char *)chunk, nread, last_frame);
118 bytes_processed += nread;
119
120 if (last_frame)
121 return 0;
122 else
123 return EMOREDATA;
124 }
125
serial_in_use(int serial)126 int wav_reader_c::serial_in_use(int serial) {
127 return pcmpacketizer->serial_in_use(serial);
128 }
129
get_header_page(int header_type)130 ogmmerge_page_t *wav_reader_c::get_header_page(int header_type) {
131 return pcmpacketizer->get_header_page(header_type);
132 }
133
get_page()134 ogmmerge_page_t *wav_reader_c::get_page() {
135 return pcmpacketizer->get_page();
136 }
137
display_priority()138 int wav_reader_c::display_priority() {
139 return DISPLAYPRIORITY_HIGH - 1;
140 }
141
reset()142 void wav_reader_c::reset() {
143 if (pcmpacketizer != NULL)
144 pcmpacketizer->reset();
145 }
146
display_progress()147 void wav_reader_c::display_progress() {
148 int samples = (get_uint32(&wheader.riff.len) - sizeof(wheader) + 8) / bps;
149 fprintf(stdout, "progress: %d/%d seconds (%d%%)\r",
150 (int)(bytes_processed / bps), (int)samples,
151 (int)(bytes_processed * 100L / bps / samples));
152 fflush(stdout);
153 }
154
155