FFmpeg
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
libwavpackenc.c
Go to the documentation of this file.
1 /*
2  * This file is part of FFmpeg.
3  *
4  * FFmpeg is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * FFmpeg is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with FFmpeg; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17  */
18 
19 #include <wavpack/wavpack.h>
20 #include <string.h>
21 
22 #include "libavutil/attributes.h"
23 #include "libavutil/opt.h"
24 #include "libavutil/samplefmt.h"
25 
26 #include "audio_frame_queue.h"
27 #include "avcodec.h"
28 #include "internal.h"
29 
30 #define WV_DEFAULT_BLOCK_SIZE 32768
31 
32 typedef struct LibWavpackContext {
33  const AVClass *class;
36 
38  int user_size;
39 
42 
44  const AVFrame *frame, int *got_output)
45 {
46  LibWavpackContext *s = avctx->priv_data;
47  int ret;
48 
49  s->got_output = 0;
50  s->pkt = pkt;
51  s->user_size = pkt->size;
52 
53  if (frame) {
54  ret = ff_af_queue_add(&s->afq, frame);
55  if (ret < 0)
56  return ret;
57 
58  ret = WavpackPackSamples(s->wv, (int32_t*)frame->data[0], frame->nb_samples);
59  if (!ret) {
60  av_log(avctx, AV_LOG_ERROR, "Error encoding a frame: %s\n",
61  WavpackGetErrorMessage(s->wv));
62  return AVERROR_UNKNOWN;
63  }
64  }
65 
66  if (!s->got_output &&
67  (!frame || frame->nb_samples < avctx->frame_size)) {
68  ret = WavpackFlushSamples(s->wv);
69  if (!ret) {
70  av_log(avctx, AV_LOG_ERROR, "Error flushing the encoder: %s\n",
71  WavpackGetErrorMessage(s->wv));
72  return AVERROR_UNKNOWN;
73  }
74  }
75 
76  if (s->got_output) {
77  ff_af_queue_remove(&s->afq, avctx->frame_size, &pkt->pts, &pkt->duration);
78  *got_output = 1;
79  }
80 
81  return 0;
82 }
83 
84 static int encode_callback(void *id, void *data, int32_t count)
85 {
86  AVCodecContext *avctx = id;
87  LibWavpackContext *s = avctx->priv_data;
88  int ret, offset = s->pkt->size;
89 
90  if (s->user_size) {
91  if (s->user_size - count < s->pkt->size) {
92  av_log(avctx, AV_LOG_ERROR, "Provided packet too small.\n");
93  return 0;
94  }
95  s->pkt->size += count;
96  } else {
97  ret = av_grow_packet(s->pkt, count);
98  if (ret < 0) {
99  av_log(avctx, AV_LOG_ERROR, "Error allocating output packet.\n");
100  return 0;
101  }
102  }
103 
104  memcpy(s->pkt->data + offset, data, count);
105 
106  s->got_output = 1;
107 
108  return 1;
109 }
110 
112 {
113  LibWavpackContext *s = avctx->priv_data;
114  WavpackConfig config = { 0 };
115  int ret;
116 
117  s->wv = WavpackOpenFileOutput(encode_callback, avctx, NULL);
118  if (!s->wv) {
119  av_log(avctx, AV_LOG_ERROR, "Error allocating the encoder.\n");
120  return AVERROR(ENOMEM);
121  }
122 
123  if (!avctx->frame_size)
125 
126  config.bytes_per_sample = 4;
127  config.bits_per_sample = 32;
128  config.block_samples = avctx->frame_size;
129  config.channel_mask = avctx->channel_layout;
130  config.num_channels = avctx->channels;
131  config.sample_rate = avctx->sample_rate;
132 
134  if (avctx->compression_level >= 3) {
135  config.flags |= CONFIG_VERY_HIGH_FLAG;
136 
137  if (avctx->compression_level >= 8)
138  config.xmode = 6;
139  else if (avctx->compression_level >= 7)
140  config.xmode = 5;
141  else if (avctx->compression_level >= 6)
142  config.xmode = 4;
143  else if (avctx->compression_level >= 5)
144  config.xmode = 3;
145  else if (avctx->compression_level >= 4)
146  config.xmode = 2;
147  } else if (avctx->compression_level >= 2)
148  config.flags |= CONFIG_HIGH_FLAG;
149  else if (avctx->compression_level < 1)
150  config.flags |= CONFIG_FAST_FLAG;
151  }
152 
153  ret = WavpackSetConfiguration(s->wv, &config, -1);
154  if (!ret)
155  goto fail;
156 
157  ret = WavpackPackInit(s->wv);
158  if (!ret)
159  goto fail;
160 
161  ff_af_queue_init(avctx, &s->afq);
162 
163  return 0;
164 
165 fail:
166  av_log(avctx, AV_LOG_ERROR, "Error configuring the encoder: %s.\n",
167  WavpackGetErrorMessage(s->wv));
168  WavpackCloseFile(s->wv);
169  return AVERROR_UNKNOWN;
170 }
171 
173 {
174  LibWavpackContext *s = avctx->priv_data;
175 
176  WavpackCloseFile(s->wv);
177 
178  ff_af_queue_close(&s->afq);
179 
180  return 0;
181 }
182 
184  .name = "libwavpack",
185  .type = AVMEDIA_TYPE_AUDIO,
186  .id = AV_CODEC_ID_WAVPACK,
187  .priv_data_size = sizeof(LibWavpackContext),
189  .encode2 = wavpack_encode_frame,
192  .sample_fmts = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_S32,
194 };