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