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 32typedef 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 43static 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 84static 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 111static 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 165fail: 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 172static 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 183AVCodec 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 = CODEC_CAP_DELAY | CODEC_CAP_SMALL_LAST_FRAME, 192 .sample_fmts = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_S32, 193 AV_SAMPLE_FMT_NONE }, 194}; 195