X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=libavcodec%2Froqaudioenc.c;h=f687f5cd9d9294737a84b2136679eba9d381143f;hb=e5e8a26dcf6d572e841a7a191e4c96524367e3f9;hp=df014a449f584d5659ba8d83772fe94cd12e17d6;hpb=fd76c37fd9f564b4e979fbe20ecfcfad13f8b4f4;p=ffmpeg diff --git a/libavcodec/roqaudioenc.c b/libavcodec/roqaudioenc.c index df014a449f5..f687f5cd9d9 100644 --- a/libavcodec/roqaudioenc.c +++ b/libavcodec/roqaudioenc.c @@ -4,78 +4,83 @@ * Copyright (c) 2005 Eric Lasota * Based on RoQ specs (c)2001 Tim Ferguson * - * 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 "bytestream.h" +#include "internal.h" +#include "mathops.h" -#define ROQ_FIRST_FRAME_SIZE (735*8) #define ROQ_FRAME_SIZE 735 - +#define ROQ_HEADER_SIZE 8 #define MAX_DPCM (127*127) -static unsigned char dpcmValues[MAX_DPCM]; -typedef struct -{ +typedef struct ROQDPCMContext { short lastSample[2]; -} ROQDPCMContext_t; + int input_frames; + int buffered_samples; + int16_t *frame_buffer; + int64_t first_pts; +} ROQDPCMContext; -static av_cold void roq_dpcm_table_init(void) + +static av_cold int roq_dpcm_encode_close(AVCodecContext *avctx) { - int i; + ROQDPCMContext *context = avctx->priv_data; - /* Create a table of quick DPCM values */ - for (i=0; imid); - } + av_freep(&context->frame_buffer); + + return 0; } -static int roq_dpcm_encode_init(AVCodecContext *avctx) +static av_cold int roq_dpcm_encode_init(AVCodecContext *avctx) { - ROQDPCMContext_t *context = avctx->priv_data; + ROQDPCMContext *context = avctx->priv_data; + int ret; if (avctx->channels > 2) { av_log(avctx, AV_LOG_ERROR, "Audio must be mono or stereo\n"); - return -1; + return AVERROR(EINVAL); } if (avctx->sample_rate != 22050) { av_log(avctx, AV_LOG_ERROR, "Audio must be 22050 Hz\n"); - return -1; + return AVERROR(EINVAL); } - if (avctx->sample_fmt != SAMPLE_FMT_S16) { - av_log(avctx, AV_LOG_ERROR, "Audio must be signed 16-bit\n"); - return -1; - } - - roq_dpcm_table_init(); - avctx->frame_size = ROQ_FIRST_FRAME_SIZE; + avctx->frame_size = ROQ_FRAME_SIZE; + avctx->bit_rate = (ROQ_HEADER_SIZE + ROQ_FRAME_SIZE * avctx->channels) * + (22050 / ROQ_FRAME_SIZE) * 8; + + context->frame_buffer = av_malloc(8 * ROQ_FRAME_SIZE * avctx->channels * + sizeof(*context->frame_buffer)); + if (!context->frame_buffer) { + ret = AVERROR(ENOMEM); + goto error; + } context->lastSample[0] = context->lastSample[1] = 0; - avctx->coded_frame= avcodec_alloc_frame(); - avctx->coded_frame->key_frame= 1; - return 0; +error: + roq_dpcm_encode_close(avctx); + return ret; } static unsigned char dpcm_predict(short *previous, short current) @@ -92,8 +97,10 @@ static unsigned char dpcm_predict(short *previous, short current) if (diff >= MAX_DPCM) result = 127; - else - result = dpcmValues[diff]; + else { + result = ff_sqrt(diff); + result += diff > result*result+result; + } /* See if this overflows */ retry: @@ -116,28 +123,52 @@ static unsigned char dpcm_predict(short *previous, short current) return result; } -static int roq_dpcm_encode_frame(AVCodecContext *avctx, - unsigned char *frame, int buf_size, void *data) +static int roq_dpcm_encode_frame(AVCodecContext *avctx, AVPacket *avpkt, + const AVFrame *frame, int *got_packet_ptr) { - int i, samples, stereo, ch; - short *in; - unsigned char *out; - - ROQDPCMContext_t *context = avctx->priv_data; + int i, stereo, data_size, ret; + const int16_t *in = frame ? (const int16_t *)frame->data[0] : NULL; + uint8_t *out; + ROQDPCMContext *context = avctx->priv_data; stereo = (avctx->channels == 2); + if (!in && context->input_frames >= 8) + return 0; + + if (in && context->input_frames < 8) { + memcpy(&context->frame_buffer[context->buffered_samples * avctx->channels], + in, avctx->frame_size * avctx->channels * sizeof(*in)); + context->buffered_samples += avctx->frame_size; + if (context->input_frames == 0) + context->first_pts = frame->pts; + if (context->input_frames < 7) { + context->input_frames++; + return 0; + } + } + if (context->input_frames < 8) + in = context->frame_buffer; + if (stereo) { context->lastSample[0] &= 0xFF00; context->lastSample[1] &= 0xFF00; } - out = frame; - in = data; + if (context->input_frames == 7) + data_size = avctx->channels * context->buffered_samples; + else + data_size = avctx->channels * avctx->frame_size; + + if ((ret = ff_alloc_packet(avpkt, ROQ_HEADER_SIZE + data_size))) { + av_log(avctx, AV_LOG_ERROR, "Error getting output packet\n"); + return ret; + } + out = avpkt->data; bytestream_put_byte(&out, stereo ? 0x21 : 0x20); bytestream_put_byte(&out, 0x10); - bytestream_put_le32(&out, avctx->frame_size*avctx->channels); + bytestream_put_le32(&out, data_size); if (stereo) { bytestream_put_byte(&out, (context->lastSample[1])>>8); @@ -146,34 +177,30 @@ static int roq_dpcm_encode_frame(AVCodecContext *avctx, bytestream_put_le16(&out, context->lastSample[0]); /* Write the actual samples */ - samples = avctx->frame_size; - for (i=0; ichannels; ch++) - *out++ = dpcm_predict(&context->lastSample[ch], *in++); - - /* Use smaller frames from now on */ - avctx->frame_size = ROQ_FRAME_SIZE; + for (i = 0; i < data_size; i++) + *out++ = dpcm_predict(&context->lastSample[i & 1], *in++); - /* Return the result size */ - return out - frame; -} + avpkt->pts = context->input_frames <= 7 ? context->first_pts : frame->pts; + avpkt->duration = data_size / avctx->channels; -static av_cold int roq_dpcm_encode_close(AVCodecContext *avctx) -{ - av_freep(&avctx->coded_frame); + context->input_frames++; + if (!in) + context->input_frames = FFMAX(context->input_frames, 8); + *got_packet_ptr = 1; return 0; } -AVCodec roq_dpcm_encoder = { - "roq_dpcm", - CODEC_TYPE_AUDIO, - CODEC_ID_ROQ_DPCM, - sizeof(ROQDPCMContext_t), - roq_dpcm_encode_init, - roq_dpcm_encode_frame, - roq_dpcm_encode_close, - NULL, - .sample_fmts = (enum SampleFormat[]){SAMPLE_FMT_S16,SAMPLE_FMT_NONE}, - .long_name = NULL_IF_CONFIG_SMALL("id RoQ DPCM"), +AVCodec ff_roq_dpcm_encoder = { + .name = "roq_dpcm", + .long_name = NULL_IF_CONFIG_SMALL("id RoQ DPCM"), + .type = AVMEDIA_TYPE_AUDIO, + .id = AV_CODEC_ID_ROQ_DPCM, + .priv_data_size = sizeof(ROQDPCMContext), + .init = roq_dpcm_encode_init, + .encode2 = roq_dpcm_encode_frame, + .close = roq_dpcm_encode_close, + .capabilities = AV_CODEC_CAP_DELAY, + .sample_fmts = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_S16, + AV_SAMPLE_FMT_NONE }, };