blob: 6d5708985afde36af16ae74d1b2937aeda11c451
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; |
34 | WavpackContext *wv; |
35 | AudioFrameQueue afq; |
36 | |
37 | AVPacket *pkt; |
38 | int user_size; |
39 | |
40 | int got_output; |
41 | } LibWavpackContext; |
42 | |
43 | static int wavpack_encode_frame(AVCodecContext *avctx, AVPacket *pkt, |
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 | |
111 | static av_cold int wavpack_encode_init(AVCodecContext *avctx) |
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) |
124 | avctx->frame_size = WV_DEFAULT_BLOCK_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 | |
133 | if (avctx->compression_level != FF_COMPRESSION_DEFAULT) { |
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 | |
172 | static av_cold int wavpack_encode_close(AVCodecContext *avctx) |
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 | |
183 | AVCodec ff_libwavpack_encoder = { |
184 | .name = "libwavpack", |
185 | .type = AVMEDIA_TYPE_AUDIO, |
186 | .id = AV_CODEC_ID_WAVPACK, |
187 | .priv_data_size = sizeof(LibWavpackContext), |
188 | .init = wavpack_encode_init, |
189 | .encode2 = wavpack_encode_frame, |
190 | .close = wavpack_encode_close, |
191 | .capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_SMALL_LAST_FRAME, |
192 | .sample_fmts = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_S32, |
193 | AV_SAMPLE_FMT_NONE }, |
194 | }; |
195 |