source: src/io/sink_vorbis.c @ be63940

feature/autosinkfeature/cnnfeature/crepefix/ffmpeg5
Last change on this file since be63940 was be63940, checked in by Paul Brossier <piem@piem.org>, 5 years ago

[io] avoid memory leak in sink_vorbis

  • Property mode set to 100644
File size: 7.0 KB
Line 
1/*
2  Copyright (C) 2018 Paul Brossier <piem@aubio.org>
3
4  This file is part of aubio.
5
6  aubio is free software: you can redistribute it and/or modify
7  it under the terms of the GNU General Public License as published by
8  the Free Software Foundation, either version 3 of the License, or
9  (at your option) any later version.
10
11  aubio is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  GNU General Public License for more details.
15
16  You should have received a copy of the GNU General Public License
17  along with aubio.  If not, see <http://www.gnu.org/licenses/>.
18
19*/
20
21#include "aubio_priv.h"
22
23#ifdef HAVE_VORBISENC
24
25#include "io/ioutils.h"
26#include "fmat.h"
27
28#include <vorbis/vorbisenc.h>
29#include <string.h> // strerror
30#include <errno.h> // errno
31#include <time.h> // time
32
33struct _aubio_sink_vorbis_t {
34  FILE *fid;            // file id
35  ogg_stream_state os;  // stream
36  ogg_page og;          // page
37  ogg_packet op;        // data packet
38  vorbis_info vi;       // vorbis bitstream settings
39  vorbis_comment vc;    // user comment
40  vorbis_dsp_state vd;  // working state
41  vorbis_block vb;      // working space
42
43  uint_t samplerate;
44  uint_t channels;
45  char_t *path;
46};
47
48typedef struct _aubio_sink_vorbis_t aubio_sink_vorbis_t;
49
50uint_t aubio_sink_vorbis_preset_channels(aubio_sink_vorbis_t *s,
51    uint_t channels);
52uint_t aubio_sink_vorbis_preset_samplerate(aubio_sink_vorbis_t *s,
53    uint_t samplerate);
54uint_t aubio_sink_vorbis_open(aubio_sink_vorbis_t *s);
55uint_t aubio_sink_vorbis_close (aubio_sink_vorbis_t *s);
56void del_aubio_sink_vorbis (aubio_sink_vorbis_t *s);
57
58aubio_sink_vorbis_t * new_aubio_sink_vorbis (const char_t *uri,
59    uint_t samplerate)
60{
61  aubio_sink_vorbis_t * s = AUBIO_NEW(aubio_sink_vorbis_t);
62
63  s->path = AUBIO_ARRAY(char_t, strnlen(uri, PATH_MAX) + 1);
64  strncpy(s->path, uri, strnlen(uri, PATH_MAX) + 1);
65  s->path[strnlen(uri, PATH_MAX)] = '\0';
66
67  s->channels = 0;
68
69  if ((sint_t)samplerate == 0)
70    return s;
71
72  aubio_sink_vorbis_preset_samplerate(s, samplerate);
73  s->channels = 1;
74
75  if (aubio_sink_vorbis_open(s) != AUBIO_OK)
76    goto failure;
77
78  return s;
79
80failure:
81  del_aubio_sink_vorbis(s);
82  return NULL;
83}
84
85void del_aubio_sink_vorbis (aubio_sink_vorbis_t *s)
86{
87  if (s->fid) aubio_sink_vorbis_close(s);
88  // clean up
89  ogg_stream_clear(&s->os);
90  vorbis_block_clear(&s->vb);
91  vorbis_dsp_clear(&s->vd);
92  vorbis_comment_clear(&s->vc);
93  vorbis_info_clear(&s->vi);
94
95  if (s->path) AUBIO_FREE(s->path);
96  AUBIO_FREE(s);
97}
98
99uint_t aubio_sink_vorbis_open(aubio_sink_vorbis_t *s)
100{
101  float quality_mode = .9;
102
103  if (s->samplerate == 0 || s->channels == 0)
104  {
105    AUBIO_ERR("sink_vorbis: vorbis_encode_init_vbr failed\n");
106    return AUBIO_FAIL;
107  }
108
109  s->fid = fopen((const char *)s->path, "wb");
110  if (!s->fid) return AUBIO_FAIL;
111
112  vorbis_info_init(&s->vi);
113  if (vorbis_encode_init_vbr(&s->vi, s->channels, s->samplerate, quality_mode))
114  {
115    AUBIO_ERR("sink_vorbis: vorbis_encode_init_vbr failed\n");
116    return AUBIO_FAIL;
117  }
118
119  // add comment
120  vorbis_comment_init(&s->vc);
121  vorbis_comment_add_tag(&s->vc, "ENCODER", "aubio");
122
123  // initalise analysis and block
124  vorbis_analysis_init(&s->vd, &s->vi);
125  vorbis_block_init(&s->vd, &s->vb);
126
127  // pick randome serial number
128  srand(time(NULL));
129  ogg_stream_init(&s->os, rand());
130
131  // write header
132  {
133    int ret = 0;
134    ogg_packet header;
135    ogg_packet header_comm;
136    ogg_packet header_code;
137
138    vorbis_analysis_headerout(&s->vd, &s->vc, &header, &header_comm,
139        &header_code);
140
141    ogg_stream_packetin(&s->os, &header);
142    ogg_stream_packetin(&s->os, &header_comm);
143    ogg_stream_packetin(&s->os, &header_code);
144
145    // make sure audio data will start on a new page
146    while (1)
147    {
148      ret = ogg_stream_flush(&s->os, &s->og);
149      if (ret==0) break;
150      fwrite(s->og.header, 1, s->og.header_len, s->fid);
151      fwrite(s->og.body,   1, s->og.body_len,   s->fid);
152    }
153  }
154
155  return AUBIO_OK;
156}
157
158uint_t aubio_sink_vorbis_preset_samplerate(aubio_sink_vorbis_t *s,
159    uint_t samplerate)
160{
161  if (aubio_io_validate_samplerate("sink_vorbis", s->path, samplerate))
162    return AUBIO_FAIL;
163  s->samplerate = samplerate;
164  if (s->samplerate != 0 && s->channels != 0)
165    return aubio_sink_vorbis_open(s);
166  return AUBIO_OK;
167}
168
169uint_t aubio_sink_vorbis_preset_channels(aubio_sink_vorbis_t *s,
170    uint_t channels)
171{
172  if (aubio_io_validate_channels("sink_vorbis", s->path, channels)) {
173    return AUBIO_FAIL;
174  }
175  s->channels = channels;
176  // automatically open when both samplerate and channels have been set
177  if (s->samplerate != 0 && s->channels != 0) {
178    return aubio_sink_vorbis_open(s);
179  }
180  return AUBIO_OK;
181}
182
183uint_t aubio_sink_vorbis_get_samplerate(const aubio_sink_vorbis_t *s)
184{
185  return s->samplerate;
186}
187
188uint_t aubio_sink_vorbis_get_channels(const aubio_sink_vorbis_t *s)
189{
190  return s->channels;
191}
192
193void aubio_sink_vorbis_write(aubio_sink_vorbis_t *s)
194{
195  // pre-analysis
196  while (vorbis_analysis_blockout(&s->vd, &s->vb) == 1) {
197
198    vorbis_analysis(&s->vb, NULL);
199    vorbis_bitrate_addblock(&s->vb);
200
201    while (vorbis_bitrate_flushpacket(&s->vd, &s->op))
202    {
203      ogg_stream_packetin(&s->os, &s->op);
204
205      while (1) {
206        int result = ogg_stream_pageout (&s->os, &s->og);
207        if (result == 0) break;
208        fwrite(s->og.header, 1, s->og.header_len, s->fid);
209        fwrite(s->og.body,   1, s->og.body_len,   s->fid);
210        if (ogg_page_eos(&s->og)) break;
211      }
212    }
213  }
214}
215
216void aubio_sink_vorbis_do(aubio_sink_vorbis_t *s, fvec_t *write_data,
217    uint_t write)
218{
219  uint_t c, v;
220  float **buffer = vorbis_analysis_buffer(&s->vd, (long)write);
221  // fill buffer
222  if (!write) {
223    return;
224  } else if (!buffer) {
225    AUBIO_WRN("sink_vorbis: failed fetching buffer of size %d\n", write);
226    return;
227  } else {
228    for (c = 0; c < s->channels; c++) {
229      for (v = 0; v < write; v++) {
230        buffer[c][v] = write_data->data[v];
231      }
232    }
233    // tell vorbis how many frames were written
234    vorbis_analysis_wrote(&s->vd, (long)write);
235  }
236  // write to file
237  aubio_sink_vorbis_write(s);
238}
239
240void aubio_sink_vorbis_do_multi(aubio_sink_vorbis_t *s, fmat_t *write_data,
241    uint_t write)
242{
243  uint_t c, v;
244  float **buffer = vorbis_analysis_buffer(&s->vd, (long)write);
245  // fill buffer
246  if (!write) {
247    return;
248  } else if (!buffer) {
249    AUBIO_WRN("sink_vorbis: failed fetching buffer of size %d\n", write);
250    return;
251  } else {
252    for (c = 0; c < s->channels; c++) {
253      for (v = 0; v < write; v++) {
254        buffer[c][v] = write_data->data[c][v];
255      }
256    }
257    // tell vorbis how many frames were written
258    vorbis_analysis_wrote(&s->vd, (long)write);
259  }
260
261  aubio_sink_vorbis_write(s);
262}
263
264uint_t aubio_sink_vorbis_close (aubio_sink_vorbis_t *s)
265{
266  //mark the end of stream
267  vorbis_analysis_wrote(&s->vd, 0);
268
269  aubio_sink_vorbis_write(s);
270
271  if (fclose(s->fid)) {
272    AUBIO_ERR("sink_vorbis: Error closing file %s (%s)\n",
273        s->path, strerror(errno));
274    return AUBIO_FAIL;
275  }
276  return AUBIO_OK;
277}
278
279#endif /* HAVE_VORBISENC */
Note: See TracBrowser for help on using the repository browser.