X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=libavcodec%2Flibgsm.c;h=1fa04cf9d95b7492402d9c547c0bbd0fd00b948c;hb=0a60780c7fe72e2f9cc41efc152b3807954b7820;hp=82e00b1f51254bfb05afe4d4afa9c8e359baec91;hpb=96ddaff5ec76f40d4ea6d00f07ff246388db4835;p=ffmpeg diff --git a/libavcodec/libgsm.c b/libavcodec/libgsm.c index 82e00b1f512..1fa04cf9d95 100644 --- a/libavcodec/libgsm.c +++ b/libavcodec/libgsm.c @@ -3,55 +3,55 @@ * Copyright (c) 2005 Alban Bedel * Copyright (c) 2006, 2007 Michel Bardiaux * - * 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 */ /** - * @file libgsm.c + * @file * Interface to libgsm for gsm encoding/decoding */ // The idiosyncrasies of GSM-in-WAV are explained at http://kbs.cs.tu-berlin.de/~jutta/toast.html -#include "avcodec.h" -#include +#include -// gsm.h misses some essential constants -#define GSM_BLOCK_SIZE 33 -#define GSM_MS_BLOCK_SIZE 65 -#define GSM_FRAME_SIZE 160 +#include "avcodec.h" +#include "gsm.h" -static av_cold int libgsm_init(AVCodecContext *avctx) { +static av_cold int libgsm_encode_init(AVCodecContext *avctx) { if (avctx->channels > 1) { av_log(avctx, AV_LOG_ERROR, "Mono required for GSM, got %d channels\n", avctx->channels); return -1; } + if (avctx->sample_rate != 8000) { av_log(avctx, AV_LOG_ERROR, "Sample rate 8000Hz required for GSM, got %dHz\n", avctx->sample_rate); - return -1; + if (avctx->strict_std_compliance > FF_COMPLIANCE_UNOFFICIAL) + return -1; } if (avctx->bit_rate != 13000 /* Official */ && avctx->bit_rate != 13200 /* Very common */ && avctx->bit_rate != 0 /* Unknown; a.o. mov does not set bitrate when decoding */ ) { av_log(avctx, AV_LOG_ERROR, "Bitrate 13000bps required for GSM, got %dbps\n", avctx->bit_rate); - return -1; + if (avctx->strict_std_compliance > FF_COMPLIANCE_UNOFFICIAL) + return -1; } avctx->priv_data = gsm_create(); @@ -75,7 +75,8 @@ static av_cold int libgsm_init(AVCodecContext *avctx) { return 0; } -static av_cold int libgsm_close(AVCodecContext *avctx) { +static av_cold int libgsm_encode_close(AVCodecContext *avctx) { + av_freep(&avctx->coded_frame); gsm_destroy(avctx->priv_data); avctx->priv_data = NULL; return 0; @@ -98,63 +99,146 @@ static int libgsm_encode_frame(AVCodecContext *avctx, } -AVCodec libgsm_encoder = { - "libgsm", - CODEC_TYPE_AUDIO, - CODEC_ID_GSM, - 0, - libgsm_init, - libgsm_encode_frame, - libgsm_close, +AVCodec ff_libgsm_encoder = { + .name = "libgsm", + .type = AVMEDIA_TYPE_AUDIO, + .id = CODEC_ID_GSM, + .init = libgsm_encode_init, + .encode = libgsm_encode_frame, + .close = libgsm_encode_close, + .sample_fmts = (const enum AVSampleFormat[]){AV_SAMPLE_FMT_S16,AV_SAMPLE_FMT_NONE}, + .long_name = NULL_IF_CONFIG_SMALL("libgsm GSM"), }; -AVCodec libgsm_ms_encoder = { - "libgsm_ms", - CODEC_TYPE_AUDIO, - CODEC_ID_GSM_MS, - 0, - libgsm_init, - libgsm_encode_frame, - libgsm_close, +AVCodec ff_libgsm_ms_encoder = { + .name = "libgsm_ms", + .type = AVMEDIA_TYPE_AUDIO, + .id = CODEC_ID_GSM_MS, + .init = libgsm_encode_init, + .encode = libgsm_encode_frame, + .close = libgsm_encode_close, + .sample_fmts = (const enum AVSampleFormat[]){AV_SAMPLE_FMT_S16,AV_SAMPLE_FMT_NONE}, + .long_name = NULL_IF_CONFIG_SMALL("libgsm GSM Microsoft variant"), }; -static int libgsm_decode_frame(AVCodecContext *avctx, - void *data, int *data_size, - uint8_t *buf, int buf_size) { +typedef struct LibGSMDecodeContext { + AVFrame frame; + struct gsm_state *state; +} LibGSMDecodeContext; - if(buf_size < avctx->block_align) return 0; +static av_cold int libgsm_decode_init(AVCodecContext *avctx) { + LibGSMDecodeContext *s = avctx->priv_data; + + if (avctx->channels > 1) { + av_log(avctx, AV_LOG_ERROR, "Mono required for GSM, got %d channels\n", + avctx->channels); + return -1; + } + + if (!avctx->channels) + avctx->channels = 1; + + if (!avctx->sample_rate) + avctx->sample_rate = 8000; + + avctx->sample_fmt = AV_SAMPLE_FMT_S16; + + s->state = gsm_create(); switch(avctx->codec_id) { case CODEC_ID_GSM: - if(gsm_decode(avctx->priv_data,buf,data)) return -1; - *data_size = GSM_FRAME_SIZE*sizeof(int16_t); + avctx->frame_size = GSM_FRAME_SIZE; + avctx->block_align = GSM_BLOCK_SIZE; break; - case CODEC_ID_GSM_MS: - if(gsm_decode(avctx->priv_data,buf,data) || - gsm_decode(avctx->priv_data,buf+33,((int16_t*)data)+GSM_FRAME_SIZE)) return -1; - *data_size = GSM_FRAME_SIZE*sizeof(int16_t)*2; + case CODEC_ID_GSM_MS: { + int one = 1; + gsm_option(s->state, GSM_OPT_WAV49, &one); + avctx->frame_size = 2 * GSM_FRAME_SIZE; + avctx->block_align = GSM_MS_BLOCK_SIZE; + } + } + + avcodec_get_frame_defaults(&s->frame); + avctx->coded_frame = &s->frame; + + return 0; +} + +static av_cold int libgsm_decode_close(AVCodecContext *avctx) { + LibGSMDecodeContext *s = avctx->priv_data; + + gsm_destroy(s->state); + s->state = NULL; + return 0; +} + +static int libgsm_decode_frame(AVCodecContext *avctx, void *data, + int *got_frame_ptr, AVPacket *avpkt) +{ + int i, ret; + LibGSMDecodeContext *s = avctx->priv_data; + uint8_t *buf = avpkt->data; + int buf_size = avpkt->size; + int16_t *samples; + + if (buf_size < avctx->block_align) { + av_log(avctx, AV_LOG_ERROR, "Packet is too small\n"); + return AVERROR_INVALIDDATA; + } + + /* get output buffer */ + s->frame.nb_samples = avctx->frame_size; + if ((ret = avctx->get_buffer(avctx, &s->frame)) < 0) { + av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n"); + return ret; + } + samples = (int16_t *)s->frame.data[0]; + + for (i = 0; i < avctx->frame_size / GSM_FRAME_SIZE; i++) { + if ((ret = gsm_decode(s->state, buf, samples)) < 0) + return -1; + buf += GSM_BLOCK_SIZE; + samples += GSM_FRAME_SIZE; } + + *got_frame_ptr = 1; + *(AVFrame *)data = s->frame; + return avctx->block_align; } -AVCodec libgsm_decoder = { - "libgsm", - CODEC_TYPE_AUDIO, - CODEC_ID_GSM, - 0, - libgsm_init, - NULL, - libgsm_close, - libgsm_decode_frame, +static void libgsm_flush(AVCodecContext *avctx) { + LibGSMDecodeContext *s = avctx->priv_data; + int one = 1; + + gsm_destroy(s->state); + s->state = gsm_create(); + if (avctx->codec_id == CODEC_ID_GSM_MS) + gsm_option(s->state, GSM_OPT_WAV49, &one); +} + +AVCodec ff_libgsm_decoder = { + .name = "libgsm", + .type = AVMEDIA_TYPE_AUDIO, + .id = CODEC_ID_GSM, + .priv_data_size = sizeof(LibGSMDecodeContext), + .init = libgsm_decode_init, + .close = libgsm_decode_close, + .decode = libgsm_decode_frame, + .flush = libgsm_flush, + .capabilities = CODEC_CAP_DR1, + .long_name = NULL_IF_CONFIG_SMALL("libgsm GSM"), }; -AVCodec libgsm_ms_decoder = { - "libgsm_ms", - CODEC_TYPE_AUDIO, - CODEC_ID_GSM_MS, - 0, - libgsm_init, - NULL, - libgsm_close, - libgsm_decode_frame, +AVCodec ff_libgsm_ms_decoder = { + .name = "libgsm_ms", + .type = AVMEDIA_TYPE_AUDIO, + .id = CODEC_ID_GSM_MS, + .priv_data_size = sizeof(LibGSMDecodeContext), + .init = libgsm_decode_init, + .close = libgsm_decode_close, + .decode = libgsm_decode_frame, + .flush = libgsm_flush, + .capabilities = CODEC_CAP_DR1, + .long_name = NULL_IF_CONFIG_SMALL("libgsm GSM Microsoft variant"), };