X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=libavcodec%2Fwmaenc.c;h=35dac73149db2c8364773bb24f5c542a535bbc8c;hb=2b98377935384ecd22c2cd26106b9e03a6c9f598;hp=5f502d269c96140f325a29729badfd822b67e69a;hpb=a1fd944f7389dffbd649db7c68fd466ad32d998c;p=ffmpeg diff --git a/libavcodec/wmaenc.c b/libavcodec/wmaenc.c index 5f502d269c9..35dac73149d 100644 --- a/libavcodec/wmaenc.c +++ b/libavcodec/wmaenc.c @@ -2,24 +2,25 @@ * WMA compatible encoder * Copyright (c) 2007 Michael Niedermayer * - * This file is part of FFmpeg. + * This file is part of Libav. * - * FFmpeg is free software; you can redistribute it and/or + * Libav is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * - * FFmpeg is distributed in the hope that it will be useful, + * Libav is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public - * License along with FFmpeg; if not, write to the Free Software + * License along with Libav; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "avcodec.h" +#include "internal.h" #include "wma.h" #undef NDEBUG @@ -27,12 +28,29 @@ static int encode_init(AVCodecContext * avctx){ - WMADecodeContext *s = avctx->priv_data; + WMACodecContext *s = avctx->priv_data; int i, flags1, flags2; uint8_t *extradata; - if(avctx->channels > MAX_CHANNELS) - return -1; + s->avctx = avctx; + + if(avctx->channels > MAX_CHANNELS) { + av_log(avctx, AV_LOG_ERROR, "too many channels: got %i, need %i or fewer", + avctx->channels, MAX_CHANNELS); + return AVERROR(EINVAL); + } + + if (avctx->sample_rate > 48000) { + av_log(avctx, AV_LOG_ERROR, "sample rate is too high: %d > 48kHz", + avctx->sample_rate); + return AVERROR(EINVAL); + } + + if(avctx->bit_rate < 24*1000) { + av_log(avctx, AV_LOG_ERROR, "bitrate too low: got %i, need 24000 or higher\n", + avctx->bit_rate); + return AVERROR(EINVAL); + } /* extract flag infos */ flags1 = 0; @@ -40,44 +58,50 @@ static int encode_init(AVCodecContext * avctx){ if (avctx->codec->id == CODEC_ID_WMAV1) { extradata= av_malloc(4); avctx->extradata_size= 4; - extradata[0] = flags1; - extradata[1] = flags1>>8; - extradata[2] = flags2; - extradata[3] = flags2>>8; + AV_WL16(extradata, flags1); + AV_WL16(extradata+2, flags2); } else if (avctx->codec->id == CODEC_ID_WMAV2) { extradata= av_mallocz(10); avctx->extradata_size= 10; - extradata[0] = flags1; - extradata[1] = flags1>>8; - extradata[2] = flags1>>16; - extradata[3] = flags1>>24; - extradata[4] = flags2; - extradata[5] = flags2>>8; + AV_WL32(extradata, flags1); + AV_WL16(extradata+4, flags2); }else assert(0); avctx->extradata= extradata; s->use_exp_vlc = flags2 & 0x0001; s->use_bit_reservoir = flags2 & 0x0002; s->use_variable_block_len = flags2 & 0x0004; + if (avctx->channels == 2) + s->ms_stereo = 1; ff_wma_init(avctx, flags2); /* init MDCT */ for(i = 0; i < s->nb_block_sizes; i++) - ff_mdct_init(&s->mdct_ctx[i], s->frame_len_bits - i + 1, 0); - - avctx->block_align= - s->block_align= avctx->bit_rate*(int64_t)s->frame_len / (avctx->sample_rate*8); + ff_mdct_init(&s->mdct_ctx[i], s->frame_len_bits - i + 1, 0, 1.0); + + s->block_align = avctx->bit_rate * (int64_t)s->frame_len / + (avctx->sample_rate * 8); + s->block_align = FFMIN(s->block_align, MAX_CODED_SUPERFRAME_SIZE); + avctx->block_align = s->block_align; + avctx->bit_rate = avctx->block_align * 8LL * avctx->sample_rate / + s->frame_len; //av_log(NULL, AV_LOG_ERROR, "%d %d %d %d\n", s->block_align, avctx->bit_rate, s->frame_len, avctx->sample_rate); - avctx->frame_size= s->frame_len; + avctx->frame_size = avctx->delay = s->frame_len; + +#if FF_API_OLD_ENCODE_AUDIO + avctx->coded_frame = &s->frame; + avcodec_get_frame_defaults(avctx->coded_frame); +#endif return 0; } -static void apply_window_and_mdct(AVCodecContext * avctx, signed short * audio, int len) { - WMADecodeContext *s = avctx->priv_data; +static void apply_window_and_mdct(AVCodecContext * avctx, const signed short * audio, int len) { + WMACodecContext *s = avctx->priv_data; int window_index= s->frame_len_bits - s->block_len_bits; + FFTContext *mdct = &s->mdct_ctx[window_index]; int i, j, channel; const float * win = s->windows[window_index]; int window_len = 1 << s->block_len_bits; @@ -87,15 +111,15 @@ static void apply_window_and_mdct(AVCodecContext * avctx, signed short * audio, memcpy(s->output, s->frame_out[channel], sizeof(float)*window_len); j = channel; for (i = 0; i < len; i++, j += avctx->channels){ - s->output[i+window_len] = audio[j] / n * win[i]; - s->frame_out[channel][i] = audio[j] / n * win[window_len - i - 1]; + s->output[i+window_len] = audio[j] / n * win[window_len - i - 1]; + s->frame_out[channel][i] = audio[j] / n * win[i]; } - ff_mdct_calc(&s->mdct_ctx[window_index], s->coefs[channel], s->output, s->mdct_tmp); + mdct->mdct_calc(mdct, s->coefs[channel], s->output); } } //FIXME use for decoding too -static void init_exp(WMADecodeContext *s, int ch, int *exp_param){ +static void init_exp(WMACodecContext *s, int ch, const int *exp_param){ int n; const uint16_t *ptr; float v, *q, max_scale, *q_end; @@ -116,7 +140,7 @@ static void init_exp(WMADecodeContext *s, int ch, int *exp_param){ s->max_exponent[ch] = max_scale; } -static void encode_exp_vlc(WMADecodeContext *s, int ch, const int *exp_param){ +static void encode_exp_vlc(WMACodecContext *s, int ch, const int *exp_param){ int last_exp; const uint16_t *ptr; float *q, *q_end; @@ -135,14 +159,14 @@ static void encode_exp_vlc(WMADecodeContext *s, int ch, const int *exp_param){ int exp = *exp_param++; int code = exp - last_exp + 60; assert(code >= 0 && code < 120); - put_bits(&s->pb, ff_wma_scale_huffbits[code], ff_wma_scale_huffcodes[code]); + put_bits(&s->pb, ff_aac_scalefactor_bits[code], ff_aac_scalefactor_code[code]); /* XXX: use a table */ q+= *ptr++; last_exp= exp; } } -static int encode_block(WMADecodeContext *s, float (*src_coefs)[BLOCK_MAX_SIZE], int total_gain){ +static int encode_block(WMACodecContext *s, float (*src_coefs)[BLOCK_MAX_SIZE], int total_gain){ int v, bsize, ch, coef_nb_bits, parse_exponents; float mdct_norm; int nb_coefs[MAX_CHANNELS]; @@ -175,18 +199,19 @@ static int encode_block(WMADecodeContext *s, float (*src_coefs)[BLOCK_MAX_SIZE], } if (s->nb_channels == 2) { - put_bits(&s->pb, 1, s->ms_stereo= 1); + put_bits(&s->pb, 1, !!s->ms_stereo); } for(ch = 0; ch < s->nb_channels; ch++) { - if (s->channel_coded[ch]= 1) { //FIXME + s->channel_coded[ch] = 1; //FIXME only set channel_coded when needed, instead of always + if (s->channel_coded[ch]) { init_exp(s, ch, fixed_exp); } } for(ch = 0; ch < s->nb_channels; ch++) { if (s->channel_coded[ch]) { - int16_t *coefs1; + WMACoef *coefs1; float *coefs, *exponents, mult; int i, n; @@ -264,7 +289,7 @@ static int encode_block(WMADecodeContext *s, float (*src_coefs)[BLOCK_MAX_SIZE], for(ch = 0; ch < s->nb_channels; ch++) { if (s->channel_coded[ch]) { int run, tindex; - int16_t *ptr, *eptr; + WMACoef *ptr, *eptr; tindex = (ch == 1 && s->ms_stereo); ptr = &s->coefs1[ch][0]; eptr = ptr + nb_coefs[ch]; @@ -300,13 +325,13 @@ static int encode_block(WMADecodeContext *s, float (*src_coefs)[BLOCK_MAX_SIZE], put_bits(&s->pb, s->coef_vlcs[tindex]->huffbits[1], s->coef_vlcs[tindex]->huffcodes[1]); } if (s->version == 1 && s->nb_channels >= 2) { - align_put_bits(&s->pb); + avpriv_align_put_bits(&s->pb); } } return 0; } -static int encode_frame(WMADecodeContext *s, float (*src_coefs)[BLOCK_MAX_SIZE], uint8_t *buf, int buf_size, int total_gain){ +static int encode_frame(WMACodecContext *s, float (*src_coefs)[BLOCK_MAX_SIZE], uint8_t *buf, int buf_size, int total_gain){ init_put_bits(&s->pb, buf, buf_size); if (s->use_bit_reservoir) { @@ -316,21 +341,22 @@ static int encode_frame(WMADecodeContext *s, float (*src_coefs)[BLOCK_MAX_SIZE], return INT_MAX; } - align_put_bits(&s->pb); + avpriv_align_put_bits(&s->pb); return put_bits_count(&s->pb)/8 - s->block_align; } -static int encode_superframe(AVCodecContext *avctx, - unsigned char *buf, int buf_size, void *data){ - WMADecodeContext *s = avctx->priv_data; - short *samples = data; - int i, total_gain, best; +static int encode_superframe(AVCodecContext *avctx, AVPacket *avpkt, + const AVFrame *frame, int *got_packet_ptr) +{ + WMACodecContext *s = avctx->priv_data; + const int16_t *samples = (const int16_t *)frame->data[0]; + int i, total_gain, ret; s->block_len_bits= s->frame_len_bits; //required by non variable block len s->block_len = 1 << s->block_len_bits; - apply_window_and_mdct(avctx, samples, avctx->frame_size); + apply_window_and_mdct(avctx, samples, frame->nb_samples); if (s->ms_stereo) { float a, b; @@ -344,19 +370,25 @@ static int encode_superframe(AVCodecContext *avctx, } } + if ((ret = ff_alloc_packet(avpkt, 2 * MAX_CODED_SUPERFRAME_SIZE))) { + av_log(avctx, AV_LOG_ERROR, "Error getting output packet\n"); + return ret; + } + #if 1 total_gain= 128; for(i=64; i; i>>=1){ - int error= encode_frame(s, s->coefs, buf, buf_size, total_gain-i); + int error = encode_frame(s, s->coefs, avpkt->data, avpkt->size, + total_gain - i); if(error<0) total_gain-= i; } #else total_gain= 90; - best= encode_frame(s, s->coefs, buf, buf_size, total_gain); + best = encode_frame(s, s->coefs, avpkt->data, avpkt->size, total_gain); for(i=32; i; i>>=1){ - int scoreL= encode_frame(s, s->coefs, buf, buf_size, total_gain-i); - int scoreR= encode_frame(s, s->coefs, buf, buf_size, total_gain+i); + int scoreL = encode_frame(s, s->coefs, avpkt->data, avpkt->size, total_gain - i); + int scoreR = encode_frame(s, s->coefs, avpkt->data, avpkt->size, total_gain + i); av_log(NULL, AV_LOG_ERROR, "%d %d %d (%d)\n", scoreL, best, scoreR, total_gain); if(scoreL < FFMIN(best, scoreR)){ best = scoreL; @@ -368,35 +400,47 @@ static int encode_superframe(AVCodecContext *avctx, } #endif - encode_frame(s, s->coefs, buf, buf_size, total_gain); + if ((i = encode_frame(s, s->coefs, avpkt->data, avpkt->size, total_gain)) >= 0) { + av_log(avctx, AV_LOG_ERROR, "required frame size too large. please " + "use a higher bit rate.\n"); + return AVERROR(EINVAL); + } assert((put_bits_count(&s->pb) & 7) == 0); - i= s->block_align - (put_bits_count(&s->pb)+7)/8; - assert(i>=0); - while(i--) + while (i++) put_bits(&s->pb, 8, 'N'); flush_put_bits(&s->pb); - return pbBufPtr(&s->pb) - s->pb.buf; + + if (frame->pts != AV_NOPTS_VALUE) + avpkt->pts = frame->pts - ff_samples_to_time_base(avctx, avctx->delay); + + avpkt->size = s->block_align; + *got_packet_ptr = 1; + return 0; } -AVCodec wmav1_encoder = -{ - "wmav1", - CODEC_TYPE_AUDIO, - CODEC_ID_WMAV1, - sizeof(WMADecodeContext), - encode_init, - encode_superframe, - ff_wma_end, +AVCodec ff_wmav1_encoder = { + .name = "wmav1", + .type = AVMEDIA_TYPE_AUDIO, + .id = CODEC_ID_WMAV1, + .priv_data_size = sizeof(WMACodecContext), + .init = encode_init, + .encode2 = encode_superframe, + .close = ff_wma_end, + .sample_fmts = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_S16, + AV_SAMPLE_FMT_NONE }, + .long_name = NULL_IF_CONFIG_SMALL("Windows Media Audio 1"), }; -AVCodec wmav2_encoder = -{ - "wmav2", - CODEC_TYPE_AUDIO, - CODEC_ID_WMAV2, - sizeof(WMADecodeContext), - encode_init, - encode_superframe, - ff_wma_end, +AVCodec ff_wmav2_encoder = { + .name = "wmav2", + .type = AVMEDIA_TYPE_AUDIO, + .id = CODEC_ID_WMAV2, + .priv_data_size = sizeof(WMACodecContext), + .init = encode_init, + .encode2 = encode_superframe, + .close = ff_wma_end, + .sample_fmts = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_S16, + AV_SAMPLE_FMT_NONE }, + .long_name = NULL_IF_CONFIG_SMALL("Windows Media Audio 2"), };