00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include <vo-amrwbenc/enc_if.h>
00023
00024 #include "libavutil/avstring.h"
00025 #include "libavutil/opt.h"
00026 #include "avcodec.h"
00027 #include "internal.h"
00028
00029 #define MAX_PACKET_SIZE (1 + (477 + 7) / 8)
00030
00031 typedef struct AMRWBContext {
00032 AVClass *av_class;
00033 void *state;
00034 int mode;
00035 int last_bitrate;
00036 int allow_dtx;
00037 } AMRWBContext;
00038
00039 static const AVOption options[] = {
00040 { "dtx", "Allow DTX (generate comfort noise)", offsetof(AMRWBContext, allow_dtx), AV_OPT_TYPE_INT, { 0 }, 0, 1, AV_OPT_FLAG_AUDIO_PARAM | AV_OPT_FLAG_ENCODING_PARAM },
00041 { NULL }
00042 };
00043
00044 static const AVClass class = {
00045 "libvo_amrwbenc", av_default_item_name, options, LIBAVUTIL_VERSION_INT
00046 };
00047
00048 static int get_wb_bitrate_mode(int bitrate, void *log_ctx)
00049 {
00050
00051 static const int rates[] = { 6600, 8850, 12650, 14250, 15850, 18250,
00052 19850, 23050, 23850 };
00053 int i, best = -1, min_diff = 0;
00054 char log_buf[200];
00055
00056 for (i = 0; i < 9; i++) {
00057 if (rates[i] == bitrate)
00058 return i;
00059 if (best < 0 || abs(rates[i] - bitrate) < min_diff) {
00060 best = i;
00061 min_diff = abs(rates[i] - bitrate);
00062 }
00063 }
00064
00065 snprintf(log_buf, sizeof(log_buf), "bitrate not supported: use one of ");
00066 for (i = 0; i < 9; i++)
00067 av_strlcatf(log_buf, sizeof(log_buf), "%.2fk, ", rates[i] / 1000.f);
00068 av_strlcatf(log_buf, sizeof(log_buf), "using %.2fk", rates[best] / 1000.f);
00069 av_log(log_ctx, AV_LOG_WARNING, "%s\n", log_buf);
00070
00071 return best;
00072 }
00073
00074 static av_cold int amr_wb_encode_init(AVCodecContext *avctx)
00075 {
00076 AMRWBContext *s = avctx->priv_data;
00077
00078 if (avctx->sample_rate != 16000) {
00079 av_log(avctx, AV_LOG_ERROR, "Only 16000Hz sample rate supported\n");
00080 return AVERROR(ENOSYS);
00081 }
00082
00083 if (avctx->channels != 1) {
00084 av_log(avctx, AV_LOG_ERROR, "Only mono supported\n");
00085 return AVERROR(ENOSYS);
00086 }
00087
00088 s->mode = get_wb_bitrate_mode(avctx->bit_rate, avctx);
00089 s->last_bitrate = avctx->bit_rate;
00090
00091 avctx->frame_size = 320;
00092 avctx->delay = 80;
00093 #if FF_API_OLD_ENCODE_AUDIO
00094 avctx->coded_frame = avcodec_alloc_frame();
00095 if (!avctx->coded_frame)
00096 return AVERROR(ENOMEM);
00097 #endif
00098
00099 s->state = E_IF_init();
00100
00101 return 0;
00102 }
00103
00104 static int amr_wb_encode_close(AVCodecContext *avctx)
00105 {
00106 AMRWBContext *s = avctx->priv_data;
00107
00108 E_IF_exit(s->state);
00109 av_freep(&avctx->coded_frame);
00110 return 0;
00111 }
00112
00113 static int amr_wb_encode_frame(AVCodecContext *avctx, AVPacket *avpkt,
00114 const AVFrame *frame, int *got_packet_ptr)
00115 {
00116 AMRWBContext *s = avctx->priv_data;
00117 const int16_t *samples = (const int16_t *)frame->data[0];
00118 int size, ret;
00119
00120 if ((ret = ff_alloc_packet2(avctx, avpkt, MAX_PACKET_SIZE)))
00121 return ret;
00122
00123 if (s->last_bitrate != avctx->bit_rate) {
00124 s->mode = get_wb_bitrate_mode(avctx->bit_rate, avctx);
00125 s->last_bitrate = avctx->bit_rate;
00126 }
00127 size = E_IF_encode(s->state, s->mode, samples, avpkt->data, s->allow_dtx);
00128 if (size <= 0 || size > MAX_PACKET_SIZE) {
00129 av_log(avctx, AV_LOG_ERROR, "Error encoding frame\n");
00130 return AVERROR(EINVAL);
00131 }
00132
00133 if (frame->pts != AV_NOPTS_VALUE)
00134 avpkt->pts = frame->pts - ff_samples_to_time_base(avctx, avctx->delay);
00135
00136 avpkt->size = size;
00137 *got_packet_ptr = 1;
00138 return 0;
00139 }
00140
00141 AVCodec ff_libvo_amrwbenc_encoder = {
00142 .name = "libvo_amrwbenc",
00143 .type = AVMEDIA_TYPE_AUDIO,
00144 .id = CODEC_ID_AMR_WB,
00145 .priv_data_size = sizeof(AMRWBContext),
00146 .init = amr_wb_encode_init,
00147 .encode2 = amr_wb_encode_frame,
00148 .close = amr_wb_encode_close,
00149 .sample_fmts = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_S16,
00150 AV_SAMPLE_FMT_NONE },
00151 .long_name = NULL_IF_CONFIG_SMALL("Android VisualOn Adaptive "
00152 "Multi-Rate (AMR) Wide-Band"),
00153 .priv_class = &class,
00154 };