~ubuntu-branches/ubuntu/wily/mkvtoolnix/wily

« back to all changes in this revision

Viewing changes to src/extract/xtr_wav.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Clément Stenac
  • Date: 2005-09-07 19:54:42 UTC
  • Revision ID: james.westby@ubuntu.com-20050907195442-funmigmy8ua340hq
Tags: upstream-1.5.6
Import upstream version 1.5.6

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
   mkvextract -- extract tracks from Matroska files into other files
 
3
 
 
4
   Distributed under the GPL
 
5
   see the file COPYING for details
 
6
   or visit http://www.gnu.org/copyleft/gpl.html
 
7
 
 
8
   $Id: xtr_wav.cpp 2882 2005-04-07 17:15:31Z mosu $
 
9
 
 
10
   extracts tracks from Matroska files into other files
 
11
 
 
12
   Written by Moritz Bunkus <moritz@bunkus.org>
 
13
   and Steve Lhomme <steve.lhomme@free.fr>.
 
14
*/
 
15
 
 
16
#include "os.h"
 
17
 
 
18
#include <matroska/KaxBlock.h>
 
19
 
 
20
#include "common.h"
 
21
#include "commonebml.h"
 
22
#include "xtr_wav.h"
 
23
 
 
24
xtr_wav_c::xtr_wav_c(const string &_codec_id,
 
25
                     int64_t _tid,
 
26
                     track_spec_t &tspec):
 
27
  xtr_base_c(_codec_id, _tid, tspec) {
 
28
 
 
29
  memset(&wh, 0, sizeof(wave_header));
 
30
}
 
31
 
 
32
void
 
33
xtr_wav_c::create_file(xtr_base_c *_master,
 
34
                       KaxTrackEntry &track) {
 
35
  int channels, sfreq, bps;
 
36
 
 
37
  channels = kt_get_a_channels(track);
 
38
  sfreq = (int)kt_get_a_sfreq(track);
 
39
  bps = kt_get_a_bps(track);
 
40
  if (-1 == bps)
 
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());
 
44
 
 
45
  xtr_base_c::create_file(_master, track);
 
46
 
 
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);
 
58
 
 
59
  out->write(&wh, sizeof(wave_header));
 
60
}
 
61
 
 
62
void
 
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));
 
68
}
 
69
 
 
70
// ------------------------------------------------------------------------
 
71
 
 
72
xtr_wavpack4_c::xtr_wavpack4_c(const string &_codec_id,
 
73
                               int64_t _tid,
 
74
                               track_spec_t &tspec):
 
75
  xtr_base_c(_codec_id, _tid, tspec),
 
76
  number_of_samples(0), extract_blockadd_level(tspec.extract_blockadd_level),
 
77
  corr_out(NULL) {
 
78
}
 
79
 
 
80
void
 
81
xtr_wavpack4_c::create_file(xtr_base_c *_master,
 
82
                            KaxTrackEntry &track) {
 
83
  KaxCodecPrivate *priv;
 
84
 
 
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);
 
90
 
 
91
  channels = kt_get_a_channels(track);
 
92
 
 
93
  xtr_base_c::create_file(_master, track);
 
94
 
 
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('.');
 
98
 
 
99
    if ((string::npos != pos) && (0 != pos))
 
100
      corr_name.erase(pos + 1);
 
101
    corr_name += "wvc";
 
102
    try {
 
103
      corr_out = new mm_file_io_c(corr_name, MODE_CREATE);
 
104
    } catch (...) {
 
105
      mxerror(" The file '%s' could not be opened for writing (%s).\n",
 
106
              corr_name.c_str(), strerror(errno));
 
107
    }
 
108
  }
 
109
}
 
110
 
 
111
void
 
112
xtr_wavpack4_c::handle_block(KaxBlock &block,
 
113
                             KaxBlockAdditions *additions,
 
114
                             int64_t timecode,
 
115
                             int64_t duration,
 
116
                             int64_t bref,
 
117
                             int64_t fref) {
 
118
  binary wv_header[32], *mybuffer;
 
119
  int i, data_size;
 
120
  vector<uint32_t> flags;
 
121
 
 
122
  for (i = 0; i < block.NumberFrames(); i++) {
 
123
    DataBuffer &data = block.GetBuffer(i);
 
124
 
 
125
    // build the main header
 
126
 
 
127
    wv_header[0] = 'w';
 
128
    wv_header[1] = 'v';
 
129
    wv_header[2] = 'p';
 
130
    wv_header[3] = 'k';
 
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);
 
142
 
 
143
    // rest of the header:
 
144
    memcpy(&wv_header[20], mybuffer, 3 * sizeof(uint32_t));
 
145
    // support multi-track files
 
146
    if (channels > 2) {
 
147
      uint32_t block_size = get_uint32_le(&mybuffer[12]);
 
148
 
 
149
      flags.clear();
 
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]);
 
153
      mybuffer += 16;
 
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);
 
163
        mybuffer += 12;
 
164
        out->write(mybuffer, block_size);
 
165
        mybuffer += block_size;
 
166
        data_size -= block_size + 12;
 
167
      }
 
168
    } else {
 
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
 
172
    }
 
173
 
 
174
    // support hybrid mode data
 
175
    if ((NULL != corr_out) && (NULL != additions)) {
 
176
      KaxBlockMore *block_more = FINDFIRST(additions, KaxBlockMore);
 
177
 
 
178
      if (block_more == NULL)
 
179
        break;
 
180
      KaxBlockAdditional *block_addition =
 
181
        FINDFIRST(block_more, KaxBlockAdditional);
 
182
      if (block_addition == NULL)
 
183
        break;
 
184
 
 
185
      data_size = block_addition->GetSize();
 
186
      mybuffer = block_addition->GetBuffer();
 
187
      if (channels > 2) {
 
188
        size_t flags_index = 0;
 
189
 
 
190
        while (data_size > 0) {
 
191
          uint32_t block_size = get_uint32_le(&mybuffer[4]);
 
192
 
 
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);
 
197
          mybuffer += 8;
 
198
          corr_out->write(mybuffer, block_size);
 
199
          mybuffer += block_size;
 
200
          data_size -= 8 + block_size;
 
201
        }
 
202
      } else {
 
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);
 
207
      }
 
208
    }
 
209
  }
 
210
}
 
211
 
 
212
void
 
213
xtr_wavpack4_c::finish_file() {
 
214
  out->setFilePointer(12);
 
215
  out->write_uint32_le(number_of_samples);
 
216
 
 
217
  if (NULL != corr_out) {
 
218
    corr_out->setFilePointer(12);
 
219
    corr_out->write_uint32_le(number_of_samples);
 
220
    delete corr_out;
 
221
  }
 
222
}