1/* 2 * RoQ audio encoder 3 * 4 * Copyright (c) 2005 Eric Lasota 5 * Based on RoQ specs (c)2001 Tim Ferguson 6 * 7 * This file is part of FFmpeg. 8 * 9 * FFmpeg is free software; you can redistribute it and/or 10 * modify it under the terms of the GNU Lesser General Public 11 * License as published by the Free Software Foundation; either 12 * version 2.1 of the License, or (at your option) any later version. 13 * 14 * FFmpeg is distributed in the hope that it will be useful, 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 * Lesser General Public License for more details. 18 * 19 * You should have received a copy of the GNU Lesser General Public 20 * License along with FFmpeg; if not, write to the Free Software 21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 22 */ 23 24#include "avcodec.h" 25#include "bytestream.h" 26 27#define ROQ_FIRST_FRAME_SIZE (735*8) 28#define ROQ_FRAME_SIZE 735 29 30 31#define MAX_DPCM (127*127) 32static unsigned char dpcmValues[MAX_DPCM]; 33 34 35typedef struct 36{ 37 short lastSample[2]; 38} ROQDPCMContext; 39 40static av_cold void roq_dpcm_table_init(void) 41{ 42 int i; 43 44 /* Create a table of quick DPCM values */ 45 for (i=0; i<MAX_DPCM; i++) { 46 int s= ff_sqrt(i); 47 int mid= s*s + s; 48 dpcmValues[i]= s + (i>mid); 49 } 50} 51 52static av_cold int roq_dpcm_encode_init(AVCodecContext *avctx) 53{ 54 ROQDPCMContext *context = avctx->priv_data; 55 56 if (avctx->channels > 2) { 57 av_log(avctx, AV_LOG_ERROR, "Audio must be mono or stereo\n"); 58 return -1; 59 } 60 if (avctx->sample_rate != 22050) { 61 av_log(avctx, AV_LOG_ERROR, "Audio must be 22050 Hz\n"); 62 return -1; 63 } 64 if (avctx->sample_fmt != SAMPLE_FMT_S16) { 65 av_log(avctx, AV_LOG_ERROR, "Audio must be signed 16-bit\n"); 66 return -1; 67 } 68 69 roq_dpcm_table_init(); 70 71 avctx->frame_size = ROQ_FIRST_FRAME_SIZE; 72 73 context->lastSample[0] = context->lastSample[1] = 0; 74 75 avctx->coded_frame= avcodec_alloc_frame(); 76 avctx->coded_frame->key_frame= 1; 77 78 return 0; 79} 80 81static unsigned char dpcm_predict(short *previous, short current) 82{ 83 int diff; 84 int negative; 85 int result; 86 int predicted; 87 88 diff = current - *previous; 89 90 negative = diff<0; 91 diff = FFABS(diff); 92 93 if (diff >= MAX_DPCM) 94 result = 127; 95 else 96 result = dpcmValues[diff]; 97 98 /* See if this overflows */ 99 retry: 100 diff = result*result; 101 if (negative) 102 diff = -diff; 103 predicted = *previous + diff; 104 105 /* If it overflows, back off a step */ 106 if (predicted > 32767 || predicted < -32768) { 107 result--; 108 goto retry; 109 } 110 111 /* Add the sign bit */ 112 result |= negative << 7; //if (negative) result |= 128; 113 114 *previous = predicted; 115 116 return result; 117} 118 119static int roq_dpcm_encode_frame(AVCodecContext *avctx, 120 unsigned char *frame, int buf_size, void *data) 121{ 122 int i, samples, stereo, ch; 123 short *in; 124 unsigned char *out; 125 126 ROQDPCMContext *context = avctx->priv_data; 127 128 stereo = (avctx->channels == 2); 129 130 if (stereo) { 131 context->lastSample[0] &= 0xFF00; 132 context->lastSample[1] &= 0xFF00; 133 } 134 135 out = frame; 136 in = data; 137 138 bytestream_put_byte(&out, stereo ? 0x21 : 0x20); 139 bytestream_put_byte(&out, 0x10); 140 bytestream_put_le32(&out, avctx->frame_size*avctx->channels); 141 142 if (stereo) { 143 bytestream_put_byte(&out, (context->lastSample[1])>>8); 144 bytestream_put_byte(&out, (context->lastSample[0])>>8); 145 } else 146 bytestream_put_le16(&out, context->lastSample[0]); 147 148 /* Write the actual samples */ 149 samples = avctx->frame_size; 150 for (i=0; i<samples; i++) 151 for (ch=0; ch<avctx->channels; ch++) 152 *out++ = dpcm_predict(&context->lastSample[ch], *in++); 153 154 /* Use smaller frames from now on */ 155 avctx->frame_size = ROQ_FRAME_SIZE; 156 157 /* Return the result size */ 158 return out - frame; 159} 160 161static av_cold int roq_dpcm_encode_close(AVCodecContext *avctx) 162{ 163 av_freep(&avctx->coded_frame); 164 165 return 0; 166} 167 168AVCodec roq_dpcm_encoder = { 169 "roq_dpcm", 170 CODEC_TYPE_AUDIO, 171 CODEC_ID_ROQ_DPCM, 172 sizeof(ROQDPCMContext), 173 roq_dpcm_encode_init, 174 roq_dpcm_encode_frame, 175 roq_dpcm_encode_close, 176 NULL, 177 .sample_fmts = (enum SampleFormat[]){SAMPLE_FMT_S16,SAMPLE_FMT_NONE}, 178 .long_name = NULL_IF_CONFIG_SMALL("id RoQ DPCM"), 179}; 180