wip
[libopusenc.git] / src / opusenc.c
1 /* Copyright (C)2002-2017 Jean-Marc Valin
2    Copyright (C)2007-2013 Xiph.Org Foundation
3    Copyright (C)2008-2013 Gregory Maxwell
4    File: opusenc.c
5
6    Redistribution and use in source and binary forms, with or without
7    modification, are permitted provided that the following conditions
8    are met:
9
10    - Redistributions of source code must retain the above copyright
11    notice, this list of conditions and the following disclaimer.
12
13    - Redistributions in binary form must reproduce the above copyright
14    notice, this list of conditions and the following disclaimer in the
15    documentation and/or other materials provided with the distribution.
16
17    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18    ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19    LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20    A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
21    OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22    EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23    PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
24    PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
25    LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
26    NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27    SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30 #ifdef HAVE_CONFIG_H
31 #include "config.h"
32 #endif
33
34 #include <time.h>
35 #include <unistd.h>
36 #include <stdlib.h>
37 #include <stdio.h>
38 #include <assert.h>
39 #include <opus_multistream.h>
40 #include "opusenc.h"
41 #include "opus_header.h"
42
43 #define BUFFER_SAMPLES 96000
44
45 static int oe_write_page(ogg_page *page, OpusEncCallbacks *cb, void *user_data)
46 {
47    int err;
48    err = cb->write(user_data, page->header, page->header_len);
49    if (err) return -1;
50    err = cb->write(user_data, page->body, page->body_len);
51    if (err) return -1;
52    return page->header_len+page->body_len;
53 }
54
55 struct StdioObject {
56   FILE *file;
57 };
58
59 struct OggOpusEnc {
60   OpusMSEncoder *st;
61   float *buffer;
62   OpusEncCallbacks callbacks;
63   void *user_data;
64   int os_allocated;
65   ogg_stream_state os;
66   ogg_page og;
67   ogg_packet op;
68   OpusHeader header;
69   char *comment;
70   int comment_length;
71   int stream_is_init;
72 };
73
74 static int oe_flush_page(OggOpusEnc *enc) {
75   ogg_page og;
76   int ret;
77   int written = 0;
78   while ( (ret = ogg_stream_flush(&enc->os, &og)) ) {
79     if (!ret) break;
80     ret = oe_write_page(&og, &enc->callbacks, enc->user_data);
81     if (ret == -1) {
82       return -1;
83     }
84     written += ret;
85   }
86   return written;
87 }
88
89 int stdio_write(void *user_data, const unsigned char *ptr, int len) {
90   struct StdioObject *obj = (struct StdioObject*)user_data;
91   return fwrite(ptr, 1, len, obj->file) != (size_t)len;
92 }
93
94 int stdio_close(void *user_data) {
95   struct StdioObject *obj = (struct StdioObject*)user_data;
96   int ret = fclose(obj->file);
97   free(obj);
98   return ret;
99 }
100
101 static const OpusEncCallbacks stdio_callbacks = {
102   stdio_write,
103   stdio_close
104 };
105
106 /* Create a new OggOpus file. */
107 OggOpusEnc *ope_create_file(const char *path, int rate, int channels, int family, int *error) {
108   OggOpusEnc *enc;
109   struct StdioObject *obj;
110   obj = malloc(sizeof(*obj));
111   enc = ope_create_callbacks(&stdio_callbacks, obj, rate, channels, family, error);
112   if (enc == NULL || (error && *error)) {
113     return NULL;
114   }
115   obj->file = fopen(path, "wb");
116   if (!obj->file) {
117     if (error) *error = OPE_CANNOT_OPEN;
118     /* FIXME: Destroy the encoder properly. */
119     free(obj);
120     return NULL;
121   }
122   return enc;
123 }
124
125 /* Create a new OggOpus file (callback-based). */
126 OggOpusEnc *ope_create_callbacks(const OpusEncCallbacks *callbacks, void *user_data,
127     int rate, int channels, int family, int *error) {
128   OpusMSEncoder *st=NULL;
129   OggOpusEnc *enc=NULL;
130   int ret;
131   if (family != 0 && family != 1 && family != 255) {
132     if (error) *error = OPE_UNIMPLEMENTED;
133     return NULL;
134   }
135   if (channels <= 0 || channels > 255) {
136     if (error) *error = OPE_BAD_ARG;
137     return NULL;
138   }
139   if ( (enc = malloc(sizeof(*enc))) == NULL) goto fail;
140   enc->header.channels=channels;
141   enc->header.channel_mapping=family;
142   enc->header.input_sample_rate=rate;
143   enc->header.gain=0;
144   st=opus_multistream_surround_encoder_create(48000, channels, enc->header.channel_mapping,
145       &enc->header.nb_streams, &enc->header.nb_coupled,
146       enc->header.stream_map, OPUS_APPLICATION_AUDIO, &ret);
147   if (! (ret == OPUS_OK && st != NULL) ) {
148     goto fail;
149   }
150   enc->os_allocated = 0;
151   enc->stream_is_init = 0;
152   enc->comment = NULL;
153   comment_init(&enc->comment, &enc->comment_length, opus_get_version_string());
154   {
155     char encoder_string[1024];
156     snprintf(encoder_string, sizeof(encoder_string), "%s version %s", PACKAGE_NAME, PACKAGE_VERSION);
157     comment_add(&enc->comment, &enc->comment_length, "ENCODER", encoder_string);
158     comment_pad(&enc->comment, &enc->comment_length, 512);
159   }
160   if (enc->comment == NULL) goto fail;
161   if ( (enc->buffer = malloc(sizeof(*enc->buffer)*BUFFER_SAMPLES*channels)) == NULL) goto fail;
162   enc->st = st;
163   enc->callbacks = *callbacks;
164   enc->user_data = user_data;
165   return enc;
166 fail:
167   if (enc) {
168     free(enc);
169     if (enc->buffer) free(enc->buffer);
170   }
171   if (st) {
172     opus_multistream_encoder_destroy(st);
173   }
174   return NULL;
175 }
176
177 static void init_stream(OggOpusEnc *enc) {
178   time_t start_time;
179   int serialno;
180   assert(!enc->stream_is_init);
181   start_time = time(NULL);
182   srand(((getpid()&65535)<<15)^start_time);
183
184   serialno = rand();
185   if (ogg_stream_init(&enc->os, serialno) == -1) {
186     assert(0);
187     /* FIXME: How the hell do we handle that? */
188   }
189   /* FIXME: Compute preskip. */
190   enc->header.preskip = 0;
191
192   /*Write header*/
193   {
194     ogg_packet op;
195     /*The Identification Header is 19 bytes, plus a Channel Mapping Table for
196       mapping families other than 0. The Channel Mapping Table is 2 bytes +
197       1 byte per channel. Because the maximum number of channels is 255, the
198       maximum size of this header is 19 + 2 + 255 = 276 bytes.*/
199     unsigned char header_data[276];
200     int packet_size = opus_header_to_packet(&enc->header, header_data, sizeof(header_data));
201     op.packet=header_data;
202     op.bytes=packet_size;
203     op.b_o_s=1;
204     op.e_o_s=0;
205     op.granulepos=0;
206     op.packetno=0;
207     ogg_stream_packetin(&enc->os, &op);
208     oe_flush_page(enc);
209
210     op.packet = (unsigned char *)enc->comment;
211     op.bytes = enc->comment_length;
212     op.b_o_s = 0;
213     op.e_o_s = 0;
214     op.granulepos = 0;
215     op.packetno = 1;
216     ogg_stream_packetin(&enc->os, &op);
217     oe_flush_page(enc);
218   }
219   enc->stream_is_init = 1;
220 }
221
222 /* Add/encode any number of float samples to the file. */
223 int ope_write_float(OggOpusEnc *enc, float *pcm, int samples_per_channel) {
224   (void)enc;
225   (void)pcm;
226   (void)samples_per_channel;
227   return 0;
228 }
229
230 /* Add/encode any number of int16 samples to the file. */
231 int ope_write(OggOpusEnc *enc, opus_int16 *pcm, int samples_per_channel) {
232   (void)enc;
233   (void)pcm;
234   (void)samples_per_channel;
235   return 0;
236 }
237
238 static void finalize_stream(OggOpusEnc *enc) {
239   if (!enc->stream_is_init) init_stream(enc);
240 }
241
242 /* Close/finalize the stream. */
243 int ope_close_and_free(OggOpusEnc *enc) {
244   finalize_stream(enc);
245   free(enc->buffer);
246   opus_multistream_encoder_destroy(enc->st);
247   if (enc->os_allocated) ogg_stream_clear(&enc->os);
248   return OPE_OK;
249 }
250
251 /* Ends the stream and create a new stream within the same file. */
252 int ope_chain_current(OggOpusEnc *enc) {
253   (void)enc;
254   return 0;
255 }
256
257 /* Ends the stream and create a new file. */
258 int ope_continue_new_file(OggOpusEnc *enc, const char *path) {
259   (void)enc;
260   (void)path;
261   return 0;
262 }
263
264 /* Ends the stream and create a new file (callback-based). */
265 int ope_continue_new_callbacks(OggOpusEnc *enc, void *user_data) {
266   (void)enc;
267   (void)user_data;
268   return 0;
269 }
270
271 /* Add a comment to the file (can only be called before encoding samples). */
272 int ope_add_comment(OggOpusEnc *enc, char *tag, char *val) {
273   (void)enc;
274   (void)tag;
275   (void)val;
276   return OPE_OK;
277 }
278
279 /* Sets the Opus comment vendor string (optional, defaults to library info). */
280 int ope_set_vendor_string(OggOpusEnc *enc, char *vendor) {
281   (void)enc;
282   (void)vendor;
283   return OPE_OK;
284 }
285
286 /* Goes straight to the libopus ctl() functions. */
287 int ope_encoder_ctl(OggOpusEnc *enc, int request, ...) {
288   (void)enc;
289   (void)request;
290   return 0;
291 }
292
293 /* ctl()-type call for the OggOpus layer. */
294 int ope_set_params(OggOpusEnc *enc, int request, ...) {
295   (void)enc;
296   (void)request;
297   return 0;
298 }