2
mkvextract -- extract tracks from Matroska files into other files
4
Distributed under the GPL
5
see the file COPYING for details
6
or visit http://www.gnu.org/copyleft/gpl.html
8
$Id: xtr_wav.cpp 2882 2005-04-07 17:15:31Z mosu $
10
extracts tracks from Matroska files into other files
12
Written by Moritz Bunkus <moritz@bunkus.org>
13
and Steve Lhomme <steve.lhomme@free.fr>.
18
#include <matroska/KaxBlock.h>
21
#include "commonebml.h"
24
xtr_wav_c::xtr_wav_c(const string &_codec_id,
27
xtr_base_c(_codec_id, _tid, tspec) {
29
memset(&wh, 0, sizeof(wave_header));
33
xtr_wav_c::create_file(xtr_base_c *_master,
34
KaxTrackEntry &track) {
35
int channels, sfreq, bps;
37
channels = kt_get_a_channels(track);
38
sfreq = (int)kt_get_a_sfreq(track);
39
bps = kt_get_a_bps(track);
41
mxerror("Track %lld with the CodecID '%s' is missing the \"bits per "
42
"second (bps)\" element and cannot be extracted.\n",
43
tid, codec_id.c_str());
45
xtr_base_c::create_file(_master, track);
47
memcpy(&wh.riff.id, "RIFF", 4);
48
memcpy(&wh.riff.wave_id, "WAVE", 4);
49
memcpy(&wh.format.id, "fmt ", 4);
50
put_uint32_le(&wh.format.len, 16);
51
put_uint16_le(&wh.common.wFormatTag, 1);
52
put_uint16_le(&wh.common.wChannels, channels);
53
put_uint32_le(&wh.common.dwSamplesPerSec, sfreq);
54
put_uint32_le(&wh.common.dwAvgBytesPerSec, channels * sfreq * bps / 8);
55
put_uint16_le(&wh.common.wBlockAlign, 4);
56
put_uint16_le(&wh.common.wBitsPerSample, bps);
57
memcpy(&wh.data.id, "data", 4);
59
out->write(&wh, sizeof(wave_header));
63
xtr_wav_c::finish_file() {
64
out->setFilePointer(0);
65
put_uint32_le(&wh.riff.len, bytes_written + 36);
66
put_uint32_le(&wh.data.len, bytes_written);
67
out->write(&wh, sizeof(wave_header));
70
// ------------------------------------------------------------------------
72
xtr_wavpack4_c::xtr_wavpack4_c(const string &_codec_id,
75
xtr_base_c(_codec_id, _tid, tspec),
76
number_of_samples(0), extract_blockadd_level(tspec.extract_blockadd_level),
81
xtr_wavpack4_c::create_file(xtr_base_c *_master,
82
KaxTrackEntry &track) {
83
KaxCodecPrivate *priv;
85
priv = FINDFIRST(&track, KaxCodecPrivate);
86
if ((NULL == priv) || (2 > priv->GetSize()))
87
mxerror("Track %lld with the CodecID '%s' is missing the \"codec private"
88
"\" element and cannot be extracted.\n", tid, codec_id.c_str());
89
memcpy(version, priv->GetBuffer(), 2);
91
channels = kt_get_a_channels(track);
93
xtr_base_c::create_file(_master, track);
95
if ((0 != kt_get_max_blockadd_id(track)) && (0 != extract_blockadd_level)) {
96
string corr_name = file_name;
97
size_t pos = corr_name.rfind('.');
99
if ((string::npos != pos) && (0 != pos))
100
corr_name.erase(pos + 1);
103
corr_out = new mm_file_io_c(corr_name, MODE_CREATE);
105
mxerror(" The file '%s' could not be opened for writing (%s).\n",
106
corr_name.c_str(), strerror(errno));
112
xtr_wavpack4_c::handle_block(KaxBlock &block,
113
KaxBlockAdditions *additions,
118
binary wv_header[32], *mybuffer;
120
vector<uint32_t> flags;
122
for (i = 0; i < block.NumberFrames(); i++) {
123
DataBuffer &data = block.GetBuffer(i);
125
// build the main header
131
memcpy(&wv_header[8], version, 2); // version
132
wv_header[10] = 0; // track_no
133
wv_header[11] = 0; // index_no
134
wv_header[12] = 0xFF; // total_samples is unknown
135
wv_header[13] = 0xFF;
136
wv_header[14] = 0xFF;
137
wv_header[15] = 0xFF;
138
put_uint32_le(&wv_header[16], number_of_samples); // block_index
139
mybuffer = data.Buffer();
140
data_size = data.Size();
141
number_of_samples += get_uint32_le(mybuffer);
143
// rest of the header:
144
memcpy(&wv_header[20], mybuffer, 3 * sizeof(uint32_t));
145
// support multi-track files
147
uint32_t block_size = get_uint32_le(&mybuffer[12]);
150
put_uint32_le(&wv_header[4], block_size + 24); // ck_size
151
out->write(wv_header, 32);
152
flags.push_back(*(uint32_t *)&mybuffer[4]);
154
out->write(mybuffer, block_size);
155
mybuffer += block_size;
156
data_size -= block_size + 16;
157
while (data_size > 0) {
158
block_size = get_uint32_le(&mybuffer[8]);
159
memcpy(&wv_header[24], mybuffer, 8);
160
put_uint32_le(&wv_header[4], block_size + 24);
161
out->write(wv_header, 32);
162
flags.push_back(*(uint32_t *)mybuffer);
164
out->write(mybuffer, block_size);
165
mybuffer += block_size;
166
data_size -= block_size + 12;
169
put_uint32_le(&wv_header[4], data_size + 12); // ck_size
170
out->write(wv_header, 32);
171
out->write(&mybuffer[12], data_size - 12); // the rest of the
174
// support hybrid mode data
175
if ((NULL != corr_out) && (NULL != additions)) {
176
KaxBlockMore *block_more = FINDFIRST(additions, KaxBlockMore);
178
if (block_more == NULL)
180
KaxBlockAdditional *block_addition =
181
FINDFIRST(block_more, KaxBlockAdditional);
182
if (block_addition == NULL)
185
data_size = block_addition->GetSize();
186
mybuffer = block_addition->GetBuffer();
188
size_t flags_index = 0;
190
while (data_size > 0) {
191
uint32_t block_size = get_uint32_le(&mybuffer[4]);
193
put_uint32_le(&wv_header[4], block_size + 24); // ck_size
194
memcpy(&wv_header[24], &flags[flags_index++], 4); // flags
195
memcpy(&wv_header[28], mybuffer, 4); // crc
196
corr_out->write(wv_header, 32);
198
corr_out->write(mybuffer, block_size);
199
mybuffer += block_size;
200
data_size -= 8 + block_size;
203
put_uint32_le(&wv_header[4], data_size + 20); // ck_size
204
memcpy(&wv_header[28], mybuffer, 4); // crc
205
corr_out->write(wv_header, 32);
206
corr_out->write(&mybuffer[4], data_size - 4);
213
xtr_wavpack4_c::finish_file() {
214
out->setFilePointer(12);
215
out->write_uint32_le(number_of_samples);
217
if (NULL != corr_out) {
218
corr_out->setFilePointer(12);
219
corr_out->write_uint32_le(number_of_samples);