X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=libavcodec%2Flibgsm.c;h=baa65bea718a8b062cd118b636a236a5a268a102;hb=86611ff123d6ff2504931efa041bff24e5619daf;hp=0573cb33d61bd20d7acbe6ebef86b5c1b00c1b46;hpb=357d0d8fc787ea5d6ca8ba0839f94493604208a3;p=ffmpeg diff --git a/libavcodec/libgsm.c b/libavcodec/libgsm.c index 0573cb33d61..baa65bea718 100644 --- a/libavcodec/libgsm.c +++ b/libavcodec/libgsm.c @@ -27,54 +27,49 @@ // The idiosyncrasies of GSM-in-WAV are explained at http://kbs.cs.tu-berlin.de/~jutta/toast.html -#include "avcodec.h" +#include "config.h" +#if HAVE_GSM_H +#include +#else #include +#endif -// gsm.h misses some essential constants -#define GSM_BLOCK_SIZE 33 -#define GSM_MS_BLOCK_SIZE 65 -#define GSM_FRAME_SIZE 160 +#include "libavutil/channel_layout.h" +#include "libavutil/common.h" +#include "avcodec.h" +#include "internal.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->codec->decode){ - if(!avctx->channels) - avctx->channels= 1; - - if(!avctx->sample_rate) - avctx->sample_rate= 8000; - - avctx->sample_fmt = AV_SAMPLE_FMT_S16; - }else{ - if (avctx->sample_rate != 8000) { - av_log(avctx, AV_LOG_ERROR, "Sample rate 8000Hz required for GSM, got %dHz\n", - avctx->sample_rate); - 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); - if(avctx->strict_std_compliance > FF_COMPLIANCE_UNOFFICIAL) - 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); + 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); + if (avctx->strict_std_compliance > FF_COMPLIANCE_UNOFFICIAL) + return -1; } avctx->priv_data = gsm_create(); switch(avctx->codec_id) { - case CODEC_ID_GSM: + case AV_CODEC_ID_GSM: avctx->frame_size = GSM_FRAME_SIZE; avctx->block_align = GSM_BLOCK_SIZE; break; - case CODEC_ID_GSM_MS: { + case AV_CODEC_ID_GSM_MS: { int one = 1; gsm_option(avctx->priv_data, GSM_OPT_WAV49, &one); avctx->frame_size = 2*GSM_FRAME_SIZE; @@ -82,100 +77,181 @@ static av_cold int libgsm_init(AVCodecContext *avctx) { } } +#if FF_API_OLD_ENCODE_AUDIO avctx->coded_frame= avcodec_alloc_frame(); - avctx->coded_frame->key_frame= 1; + if (!avctx->coded_frame) { + gsm_destroy(avctx->priv_data); + return AVERROR(ENOMEM); + } +#endif return 0; } -static av_cold int libgsm_close(AVCodecContext *avctx) { +static av_cold int libgsm_encode_close(AVCodecContext *avctx) { +#if FF_API_OLD_ENCODE_AUDIO av_freep(&avctx->coded_frame); +#endif gsm_destroy(avctx->priv_data); avctx->priv_data = NULL; return 0; } -static int libgsm_encode_frame(AVCodecContext *avctx, - unsigned char *frame, int buf_size, void *data) { - // we need a full block - if(buf_size < avctx->block_align) return 0; +static int libgsm_encode_frame(AVCodecContext *avctx, AVPacket *avpkt, + const AVFrame *frame, int *got_packet_ptr) +{ + int ret; + gsm_signal *samples = (gsm_signal *)frame->data[0]; + struct gsm_state *state = avctx->priv_data; + + if ((ret = ff_alloc_packet(avpkt, avctx->block_align))) { + av_log(avctx, AV_LOG_ERROR, "Error getting output packet\n"); + return ret; + } switch(avctx->codec_id) { - case CODEC_ID_GSM: - gsm_encode(avctx->priv_data,data,frame); + case AV_CODEC_ID_GSM: + gsm_encode(state, samples, avpkt->data); break; - case CODEC_ID_GSM_MS: - gsm_encode(avctx->priv_data,data,frame); - gsm_encode(avctx->priv_data,((short*)data)+GSM_FRAME_SIZE,frame+32); + case AV_CODEC_ID_GSM_MS: + gsm_encode(state, samples, avpkt->data); + gsm_encode(state, samples + GSM_FRAME_SIZE, avpkt->data + 32); } - return avctx->block_align; + + *got_packet_ptr = 1; + return 0; } AVCodec ff_libgsm_encoder = { - "libgsm", - AVMEDIA_TYPE_AUDIO, - CODEC_ID_GSM, - 0, - libgsm_init, - libgsm_encode_frame, - libgsm_close, - .sample_fmts = (const enum AVSampleFormat[]){AV_SAMPLE_FMT_S16,AV_SAMPLE_FMT_NONE}, - .long_name = NULL_IF_CONFIG_SMALL("libgsm GSM"), + .name = "libgsm", + .type = AVMEDIA_TYPE_AUDIO, + .id = AV_CODEC_ID_GSM, + .init = libgsm_encode_init, + .encode2 = 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 ff_libgsm_ms_encoder = { - "libgsm_ms", - AVMEDIA_TYPE_AUDIO, - CODEC_ID_GSM_MS, - 0, - libgsm_init, - libgsm_encode_frame, - libgsm_close, - .sample_fmts = (const enum AVSampleFormat[]){AV_SAMPLE_FMT_S16,AV_SAMPLE_FMT_NONE}, - .long_name = NULL_IF_CONFIG_SMALL("libgsm GSM Microsoft variant"), + .name = "libgsm_ms", + .type = AVMEDIA_TYPE_AUDIO, + .id = AV_CODEC_ID_GSM_MS, + .init = libgsm_encode_init, + .encode2 = 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, - AVPacket *avpkt) { - uint8_t *buf = avpkt->data; - int buf_size = avpkt->size; - *data_size = 0; /* In case of error */ - if(buf_size < avctx->block_align) return -1; +typedef struct LibGSMDecodeContext { + struct gsm_state *state; +} LibGSMDecodeContext; + +static av_cold int libgsm_decode_init(AVCodecContext *avctx) { + LibGSMDecodeContext *s = avctx->priv_data; + + avctx->channels = 1; + avctx->channel_layout = AV_CH_LAYOUT_MONO; + 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); + case AV_CODEC_ID_GSM: + 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 AV_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; + } + } + + 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; + AVFrame *frame = 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 */ + frame->nb_samples = avctx->frame_size; + if ((ret = ff_get_buffer(avctx, frame)) < 0) { + av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n"); + return ret; + } + samples = (int16_t *)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; + return avctx->block_align; } +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 == AV_CODEC_ID_GSM_MS) + gsm_option(s->state, GSM_OPT_WAV49, &one); +} + AVCodec ff_libgsm_decoder = { - "libgsm", - AVMEDIA_TYPE_AUDIO, - CODEC_ID_GSM, - 0, - libgsm_init, - NULL, - libgsm_close, - libgsm_decode_frame, - .long_name = NULL_IF_CONFIG_SMALL("libgsm GSM"), + .name = "libgsm", + .type = AVMEDIA_TYPE_AUDIO, + .id = AV_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 ff_libgsm_ms_decoder = { - "libgsm_ms", - AVMEDIA_TYPE_AUDIO, - CODEC_ID_GSM_MS, - 0, - libgsm_init, - NULL, - libgsm_close, - libgsm_decode_frame, - .long_name = NULL_IF_CONFIG_SMALL("libgsm GSM Microsoft variant"), + .name = "libgsm_ms", + .type = AVMEDIA_TYPE_AUDIO, + .id = AV_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"), };